├── .gitignore ├── Bin ├── C Headers │ ├── libssh2.h │ ├── libssh2_publickey.h │ └── libssh2_sftp.h ├── README.md ├── Win32 │ └── libssh2.dll └── Win64 │ ├── Debug │ └── libssh2.dll │ └── libssh2.dll ├── CLibs ├── BuildWin32Lib.cmd ├── BuildWin64Lib.cmd ├── BuildWin64LibDebug.cmd ├── CloneLibs.cmd └── README.md ├── Demos ├── LocalForward │ └── LocalForward.dpr ├── README.md ├── SFtpSend │ └── SftpSend.dpr ├── ScpRecv │ └── ScpRecv.dpr ├── ScpSend │ └── ScpSend.dpr ├── SftpDir │ └── SftpDir.dpr ├── SftpRecv │ └── SftpRecv.dpr └── SshExec │ └── SshExec.dpr ├── LICENSE ├── README.md └── Source ├── SftpClient.pas ├── SocketUtils.pas ├── Ssh2Client.pas ├── SshTunnel.pas ├── libssh2.pas ├── libssh2_publickey.pas └── libssh2_sftp.pas /.gitignore: -------------------------------------------------------------------------------- 1 | # Uncomment these types if you want even more clean repository. But be careful. 2 | # It can make harm to an existing project source. Read explanations below. 3 | # 4 | # Resource files are binaries containing manifest, project icon and version info. 5 | # They can not be viewed as text or compared by diff-tools. Consider replacing them with .rc files. 6 | #*.res 7 | # 8 | # Type library file (binary). In old Delphi versions it should be stored. 9 | # Since Delphi 2009 it is produced from .ridl file and can safely be ignored. 10 | #*.tlb 11 | # 12 | # Diagram Portfolio file. Used by the diagram editor up to Delphi 7. 13 | # Uncomment this if you are not using diagrams or use newer Delphi version. 14 | #*.ddp 15 | # 16 | # Visual LiveBindings file. Added in Delphi XE2. 17 | # Uncomment this if you are not using LiveBindings Designer. 18 | #*.vlb 19 | # 20 | # Deployment Manager configuration file for your project. Added in Delphi XE2. 21 | # Uncomment this if it is not mobile development and you do not use remote debug feature. 22 | #*.deployproj 23 | # 24 | # C++ object files produced when C/C++ Output file generation is configured. 25 | # Uncomment this if you are not using external objects (zlib library for example). 26 | #*.obj 27 | # 28 | 29 | # Delphi compiler-generated binaries (safe to delete) 30 | *.exe 31 | *.dll 32 | *.bpl 33 | *.bpi 34 | *.dcp 35 | *.so 36 | *.apk 37 | *.drc 38 | *.map 39 | *.dres 40 | *.rsm 41 | *.tds 42 | *.dcu 43 | *.lib 44 | *.a 45 | *.o 46 | *.ocx 47 | 48 | # Delphi autogenerated files (duplicated info) 49 | *.cfg 50 | *.hpp 51 | *Resource.rc 52 | 53 | # Delphi local files (user-specific info) 54 | *.local 55 | *.identcache 56 | *.projdata 57 | *.tvsconfig 58 | *.dsk 59 | *.dproj.user 60 | 61 | # Delphi history and backups 62 | __history/ 63 | __recovery/ 64 | *.~* 65 | 66 | # Castalia statistics file (since XE7 Castalia is distributed with Delphi) 67 | *.stat 68 | 69 | # Boss dependency manager vendor folder https://github.com/HashLoad/boss 70 | modules/ 71 | /Demos/SshExec/SshExec.dproj 72 | /Demos/SshExec/SshExec.res 73 | -------------------------------------------------------------------------------- /Bin/C Headers/libssh2.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2004-2009, Sara Golemon 2 | * Copyright (c) 2009-2015 Daniel Stenberg 3 | * Copyright (c) 2010 Simon Josefsson 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, 7 | * with or without modification, are permitted provided 8 | * that the following conditions are met: 9 | * 10 | * Redistributions of source code must retain the above 11 | * copyright notice, this list of conditions and the 12 | * following disclaimer. 13 | * 14 | * Redistributions in binary form must reproduce the above 15 | * copyright notice, this list of conditions and the following 16 | * disclaimer in the documentation and/or other materials 17 | * provided with the distribution. 18 | * 19 | * Neither the name of the copyright holder nor the names 20 | * of any other contributors may be used to endorse or 21 | * promote products derived from this software without 22 | * specific prior written permission. 23 | * 24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 25 | * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 26 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 27 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 29 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 31 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 32 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 34 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 35 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 36 | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 37 | * OF SUCH DAMAGE. 38 | */ 39 | 40 | #ifndef LIBSSH2_H 41 | #define LIBSSH2_H 1 42 | 43 | #define LIBSSH2_COPYRIGHT "2004-2019 The libssh2 project and its contributors." 44 | 45 | /* We use underscore instead of dash when appending DEV in dev versions just 46 | to make the BANNER define (used by src/session.c) be a valid SSH 47 | banner. Release versions have no appended strings and may of course not 48 | have dashes either. */ 49 | #define LIBSSH2_VERSION "1.9.0" 50 | 51 | /* The numeric version number is also available "in parts" by using these 52 | defines: */ 53 | #define LIBSSH2_VERSION_MAJOR 1 54 | #define LIBSSH2_VERSION_MINOR 9 55 | #define LIBSSH2_VERSION_PATCH 0 56 | 57 | /* This is the numeric version of the libssh2 version number, meant for easier 58 | parsing and comparions by programs. The LIBSSH2_VERSION_NUM define will 59 | always follow this syntax: 60 | 61 | 0xXXYYZZ 62 | 63 | Where XX, YY and ZZ are the main version, release and patch numbers in 64 | hexadecimal (using 8 bits each). All three numbers are always represented 65 | using two digits. 1.2 would appear as "0x010200" while version 9.11.7 66 | appears as "0x090b07". 67 | 68 | This 6-digit (24 bits) hexadecimal number does not show pre-release number, 69 | and it is always a greater number in a more recent release. It makes 70 | comparisons with greater than and less than work. 71 | */ 72 | #define LIBSSH2_VERSION_NUM 0x010900 73 | 74 | /* 75 | * This is the date and time when the full source package was created. The 76 | * timestamp is not stored in the source code repo, as the timestamp is 77 | * properly set in the tarballs by the maketgz script. 78 | * 79 | * The format of the date should follow this template: 80 | * 81 | * "Mon Feb 12 11:35:33 UTC 2007" 82 | */ 83 | #define LIBSSH2_TIMESTAMP "Thu Jun 20 06:19:26 UTC 2019" 84 | 85 | #ifndef RC_INVOKED 86 | 87 | #ifdef __cplusplus 88 | extern "C" { 89 | #endif 90 | #ifdef _WIN32 91 | # include 92 | # include 93 | #endif 94 | 95 | #include 96 | #include 97 | #include 98 | #include 99 | 100 | /* Allow alternate API prefix from CFLAGS or calling app */ 101 | #ifndef LIBSSH2_API 102 | # ifdef LIBSSH2_WIN32 103 | # ifdef _WINDLL 104 | # ifdef LIBSSH2_LIBRARY 105 | # define LIBSSH2_API __declspec(dllexport) 106 | # else 107 | # define LIBSSH2_API __declspec(dllimport) 108 | # endif /* LIBSSH2_LIBRARY */ 109 | # else 110 | # define LIBSSH2_API 111 | # endif 112 | # else /* !LIBSSH2_WIN32 */ 113 | # define LIBSSH2_API 114 | # endif /* LIBSSH2_WIN32 */ 115 | #endif /* LIBSSH2_API */ 116 | 117 | #ifdef HAVE_SYS_UIO_H 118 | # include 119 | #endif 120 | 121 | #if (defined(NETWARE) && !defined(__NOVELL_LIBC__)) 122 | # include 123 | typedef unsigned char uint8_t; 124 | typedef unsigned short int uint16_t; 125 | typedef unsigned int uint32_t; 126 | typedef int int32_t; 127 | typedef unsigned long long uint64_t; 128 | typedef long long int64_t; 129 | #endif 130 | 131 | #ifdef _MSC_VER 132 | typedef unsigned char uint8_t; 133 | typedef unsigned short int uint16_t; 134 | typedef unsigned int uint32_t; 135 | typedef __int32 int32_t; 136 | typedef __int64 int64_t; 137 | typedef unsigned __int64 uint64_t; 138 | typedef unsigned __int64 libssh2_uint64_t; 139 | typedef __int64 libssh2_int64_t; 140 | #if (!defined(HAVE_SSIZE_T) && !defined(ssize_t)) 141 | typedef SSIZE_T ssize_t; 142 | #define HAVE_SSIZE_T 143 | #endif 144 | #else 145 | #include 146 | typedef unsigned long long libssh2_uint64_t; 147 | typedef long long libssh2_int64_t; 148 | #endif 149 | 150 | #ifdef WIN32 151 | typedef SOCKET libssh2_socket_t; 152 | #define LIBSSH2_INVALID_SOCKET INVALID_SOCKET 153 | #else /* !WIN32 */ 154 | typedef int libssh2_socket_t; 155 | #define LIBSSH2_INVALID_SOCKET -1 156 | #endif /* WIN32 */ 157 | 158 | /* 159 | * Determine whether there is small or large file support on windows. 160 | */ 161 | 162 | #if defined(_MSC_VER) && !defined(_WIN32_WCE) 163 | # if (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64) 164 | # define LIBSSH2_USE_WIN32_LARGE_FILES 165 | # else 166 | # define LIBSSH2_USE_WIN32_SMALL_FILES 167 | # endif 168 | #endif 169 | 170 | #if defined(__MINGW32__) && !defined(LIBSSH2_USE_WIN32_LARGE_FILES) 171 | # define LIBSSH2_USE_WIN32_LARGE_FILES 172 | #endif 173 | 174 | #if defined(__WATCOMC__) && !defined(LIBSSH2_USE_WIN32_LARGE_FILES) 175 | # define LIBSSH2_USE_WIN32_LARGE_FILES 176 | #endif 177 | 178 | #if defined(__POCC__) 179 | # undef LIBSSH2_USE_WIN32_LARGE_FILES 180 | #endif 181 | 182 | #if defined(_WIN32) && !defined(LIBSSH2_USE_WIN32_LARGE_FILES) && \ 183 | !defined(LIBSSH2_USE_WIN32_SMALL_FILES) 184 | # define LIBSSH2_USE_WIN32_SMALL_FILES 185 | #endif 186 | 187 | /* 188 | * Large file (>2Gb) support using WIN32 functions. 189 | */ 190 | 191 | #ifdef LIBSSH2_USE_WIN32_LARGE_FILES 192 | # include 193 | # include 194 | # include 195 | # define LIBSSH2_STRUCT_STAT_SIZE_FORMAT "%I64d" 196 | typedef struct _stati64 libssh2_struct_stat; 197 | typedef __int64 libssh2_struct_stat_size; 198 | #endif 199 | 200 | /* 201 | * Small file (<2Gb) support using WIN32 functions. 202 | */ 203 | 204 | #ifdef LIBSSH2_USE_WIN32_SMALL_FILES 205 | # include 206 | # include 207 | # ifndef _WIN32_WCE 208 | # define LIBSSH2_STRUCT_STAT_SIZE_FORMAT "%d" 209 | typedef struct _stat libssh2_struct_stat; 210 | typedef off_t libssh2_struct_stat_size; 211 | # endif 212 | #endif 213 | 214 | #ifndef LIBSSH2_STRUCT_STAT_SIZE_FORMAT 215 | # ifdef __VMS 216 | /* We have to roll our own format here because %z is a C99-ism we don't 217 | have. */ 218 | # if __USE_OFF64_T || __USING_STD_STAT 219 | # define LIBSSH2_STRUCT_STAT_SIZE_FORMAT "%Ld" 220 | # else 221 | # define LIBSSH2_STRUCT_STAT_SIZE_FORMAT "%d" 222 | # endif 223 | # else 224 | # define LIBSSH2_STRUCT_STAT_SIZE_FORMAT "%zd" 225 | # endif 226 | typedef struct stat libssh2_struct_stat; 227 | typedef off_t libssh2_struct_stat_size; 228 | #endif 229 | 230 | /* Part of every banner, user specified or not */ 231 | #define LIBSSH2_SSH_BANNER "SSH-2.0-libssh2_" LIBSSH2_VERSION 232 | 233 | #define LIBSSH2_SSH_DEFAULT_BANNER LIBSSH2_SSH_BANNER 234 | #define LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF LIBSSH2_SSH_DEFAULT_BANNER "\r\n" 235 | 236 | /* Default generate and safe prime sizes for 237 | diffie-hellman-group-exchange-sha1 */ 238 | #define LIBSSH2_DH_GEX_MINGROUP 1024 239 | #define LIBSSH2_DH_GEX_OPTGROUP 1536 240 | #define LIBSSH2_DH_GEX_MAXGROUP 2048 241 | 242 | /* Defaults for pty requests */ 243 | #define LIBSSH2_TERM_WIDTH 80 244 | #define LIBSSH2_TERM_HEIGHT 24 245 | #define LIBSSH2_TERM_WIDTH_PX 0 246 | #define LIBSSH2_TERM_HEIGHT_PX 0 247 | 248 | /* 1/4 second */ 249 | #define LIBSSH2_SOCKET_POLL_UDELAY 250000 250 | /* 0.25 * 120 == 30 seconds */ 251 | #define LIBSSH2_SOCKET_POLL_MAXLOOPS 120 252 | 253 | /* Maximum size to allow a payload to compress to, plays it safe by falling 254 | short of spec limits */ 255 | #define LIBSSH2_PACKET_MAXCOMP 32000 256 | 257 | /* Maximum size to allow a payload to deccompress to, plays it safe by 258 | allowing more than spec requires */ 259 | #define LIBSSH2_PACKET_MAXDECOMP 40000 260 | 261 | /* Maximum size for an inbound compressed payload, plays it safe by 262 | overshooting spec limits */ 263 | #define LIBSSH2_PACKET_MAXPAYLOAD 40000 264 | 265 | /* Malloc callbacks */ 266 | #define LIBSSH2_ALLOC_FUNC(name) void *name(size_t count, void **abstract) 267 | #define LIBSSH2_REALLOC_FUNC(name) void *name(void *ptr, size_t count, \ 268 | void **abstract) 269 | #define LIBSSH2_FREE_FUNC(name) void name(void *ptr, void **abstract) 270 | 271 | typedef struct _LIBSSH2_USERAUTH_KBDINT_PROMPT 272 | { 273 | char *text; 274 | unsigned int length; 275 | unsigned char echo; 276 | } LIBSSH2_USERAUTH_KBDINT_PROMPT; 277 | 278 | typedef struct _LIBSSH2_USERAUTH_KBDINT_RESPONSE 279 | { 280 | char *text; 281 | unsigned int length; 282 | } LIBSSH2_USERAUTH_KBDINT_RESPONSE; 283 | 284 | /* 'publickey' authentication callback */ 285 | #define LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC(name) \ 286 | int name(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, \ 287 | const unsigned char *data, size_t data_len, void **abstract) 288 | 289 | /* 'keyboard-interactive' authentication callback */ 290 | #define LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC(name_) \ 291 | void name_(const char *name, int name_len, const char *instruction, \ 292 | int instruction_len, int num_prompts, \ 293 | const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts, \ 294 | LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses, void **abstract) 295 | 296 | /* Callbacks for special SSH packets */ 297 | #define LIBSSH2_IGNORE_FUNC(name) \ 298 | void name(LIBSSH2_SESSION *session, const char *message, int message_len, \ 299 | void **abstract) 300 | 301 | #define LIBSSH2_DEBUG_FUNC(name) \ 302 | void name(LIBSSH2_SESSION *session, int always_display, const char *message, \ 303 | int message_len, const char *language, int language_len, \ 304 | void **abstract) 305 | 306 | #define LIBSSH2_DISCONNECT_FUNC(name) \ 307 | void name(LIBSSH2_SESSION *session, int reason, const char *message, \ 308 | int message_len, const char *language, int language_len, \ 309 | void **abstract) 310 | 311 | #define LIBSSH2_PASSWD_CHANGEREQ_FUNC(name) \ 312 | void name(LIBSSH2_SESSION *session, char **newpw, int *newpw_len, \ 313 | void **abstract) 314 | 315 | #define LIBSSH2_MACERROR_FUNC(name) \ 316 | int name(LIBSSH2_SESSION *session, const char *packet, int packet_len, \ 317 | void **abstract) 318 | 319 | #define LIBSSH2_X11_OPEN_FUNC(name) \ 320 | void name(LIBSSH2_SESSION *session, LIBSSH2_CHANNEL *channel, \ 321 | const char *shost, int sport, void **abstract) 322 | 323 | #define LIBSSH2_CHANNEL_CLOSE_FUNC(name) \ 324 | void name(LIBSSH2_SESSION *session, void **session_abstract, \ 325 | LIBSSH2_CHANNEL *channel, void **channel_abstract) 326 | 327 | /* I/O callbacks */ 328 | #define LIBSSH2_RECV_FUNC(name) \ 329 | ssize_t name(libssh2_socket_t socket, \ 330 | void *buffer, size_t length, \ 331 | int flags, void **abstract) 332 | #define LIBSSH2_SEND_FUNC(name) \ 333 | ssize_t name(libssh2_socket_t socket, \ 334 | const void *buffer, size_t length, \ 335 | int flags, void **abstract) 336 | 337 | /* libssh2_session_callback_set() constants */ 338 | #define LIBSSH2_CALLBACK_IGNORE 0 339 | #define LIBSSH2_CALLBACK_DEBUG 1 340 | #define LIBSSH2_CALLBACK_DISCONNECT 2 341 | #define LIBSSH2_CALLBACK_MACERROR 3 342 | #define LIBSSH2_CALLBACK_X11 4 343 | #define LIBSSH2_CALLBACK_SEND 5 344 | #define LIBSSH2_CALLBACK_RECV 6 345 | 346 | /* libssh2_session_method_pref() constants */ 347 | #define LIBSSH2_METHOD_KEX 0 348 | #define LIBSSH2_METHOD_HOSTKEY 1 349 | #define LIBSSH2_METHOD_CRYPT_CS 2 350 | #define LIBSSH2_METHOD_CRYPT_SC 3 351 | #define LIBSSH2_METHOD_MAC_CS 4 352 | #define LIBSSH2_METHOD_MAC_SC 5 353 | #define LIBSSH2_METHOD_COMP_CS 6 354 | #define LIBSSH2_METHOD_COMP_SC 7 355 | #define LIBSSH2_METHOD_LANG_CS 8 356 | #define LIBSSH2_METHOD_LANG_SC 9 357 | 358 | /* flags */ 359 | #define LIBSSH2_FLAG_SIGPIPE 1 360 | #define LIBSSH2_FLAG_COMPRESS 2 361 | 362 | typedef struct _LIBSSH2_SESSION LIBSSH2_SESSION; 363 | typedef struct _LIBSSH2_CHANNEL LIBSSH2_CHANNEL; 364 | typedef struct _LIBSSH2_LISTENER LIBSSH2_LISTENER; 365 | typedef struct _LIBSSH2_KNOWNHOSTS LIBSSH2_KNOWNHOSTS; 366 | typedef struct _LIBSSH2_AGENT LIBSSH2_AGENT; 367 | 368 | typedef struct _LIBSSH2_POLLFD { 369 | unsigned char type; /* LIBSSH2_POLLFD_* below */ 370 | 371 | union { 372 | libssh2_socket_t socket; /* File descriptors -- examined with 373 | system select() call */ 374 | LIBSSH2_CHANNEL *channel; /* Examined by checking internal state */ 375 | LIBSSH2_LISTENER *listener; /* Read polls only -- are inbound 376 | connections waiting to be accepted? */ 377 | } fd; 378 | 379 | unsigned long events; /* Requested Events */ 380 | unsigned long revents; /* Returned Events */ 381 | } LIBSSH2_POLLFD; 382 | 383 | /* Poll FD Descriptor Types */ 384 | #define LIBSSH2_POLLFD_SOCKET 1 385 | #define LIBSSH2_POLLFD_CHANNEL 2 386 | #define LIBSSH2_POLLFD_LISTENER 3 387 | 388 | /* Note: Win32 Doesn't actually have a poll() implementation, so some of these 389 | values are faked with select() data */ 390 | /* Poll FD events/revents -- Match sys/poll.h where possible */ 391 | #define LIBSSH2_POLLFD_POLLIN 0x0001 /* Data available to be read or 392 | connection available -- 393 | All */ 394 | #define LIBSSH2_POLLFD_POLLPRI 0x0002 /* Priority data available to 395 | be read -- Socket only */ 396 | #define LIBSSH2_POLLFD_POLLEXT 0x0002 /* Extended data available to 397 | be read -- Channel only */ 398 | #define LIBSSH2_POLLFD_POLLOUT 0x0004 /* Can may be written -- 399 | Socket/Channel */ 400 | /* revents only */ 401 | #define LIBSSH2_POLLFD_POLLERR 0x0008 /* Error Condition -- Socket */ 402 | #define LIBSSH2_POLLFD_POLLHUP 0x0010 /* HangUp/EOF -- Socket */ 403 | #define LIBSSH2_POLLFD_SESSION_CLOSED 0x0010 /* Session Disconnect */ 404 | #define LIBSSH2_POLLFD_POLLNVAL 0x0020 /* Invalid request -- Socket 405 | Only */ 406 | #define LIBSSH2_POLLFD_POLLEX 0x0040 /* Exception Condition -- 407 | Socket/Win32 */ 408 | #define LIBSSH2_POLLFD_CHANNEL_CLOSED 0x0080 /* Channel Disconnect */ 409 | #define LIBSSH2_POLLFD_LISTENER_CLOSED 0x0080 /* Listener Disconnect */ 410 | 411 | #define HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION 412 | /* Block Direction Types */ 413 | #define LIBSSH2_SESSION_BLOCK_INBOUND 0x0001 414 | #define LIBSSH2_SESSION_BLOCK_OUTBOUND 0x0002 415 | 416 | /* Hash Types */ 417 | #define LIBSSH2_HOSTKEY_HASH_MD5 1 418 | #define LIBSSH2_HOSTKEY_HASH_SHA1 2 419 | #define LIBSSH2_HOSTKEY_HASH_SHA256 3 420 | 421 | /* Hostkey Types */ 422 | #define LIBSSH2_HOSTKEY_TYPE_UNKNOWN 0 423 | #define LIBSSH2_HOSTKEY_TYPE_RSA 1 424 | #define LIBSSH2_HOSTKEY_TYPE_DSS 2 425 | #define LIBSSH2_HOSTKEY_TYPE_ECDSA_256 3 426 | #define LIBSSH2_HOSTKEY_TYPE_ECDSA_384 4 427 | #define LIBSSH2_HOSTKEY_TYPE_ECDSA_521 5 428 | #define LIBSSH2_HOSTKEY_TYPE_ED25519 6 429 | 430 | /* Disconnect Codes (defined by SSH protocol) */ 431 | #define SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT 1 432 | #define SSH_DISCONNECT_PROTOCOL_ERROR 2 433 | #define SSH_DISCONNECT_KEY_EXCHANGE_FAILED 3 434 | #define SSH_DISCONNECT_RESERVED 4 435 | #define SSH_DISCONNECT_MAC_ERROR 5 436 | #define SSH_DISCONNECT_COMPRESSION_ERROR 6 437 | #define SSH_DISCONNECT_SERVICE_NOT_AVAILABLE 7 438 | #define SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED 8 439 | #define SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE 9 440 | #define SSH_DISCONNECT_CONNECTION_LOST 10 441 | #define SSH_DISCONNECT_BY_APPLICATION 11 442 | #define SSH_DISCONNECT_TOO_MANY_CONNECTIONS 12 443 | #define SSH_DISCONNECT_AUTH_CANCELLED_BY_USER 13 444 | #define SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE 14 445 | #define SSH_DISCONNECT_ILLEGAL_USER_NAME 15 446 | 447 | /* Error Codes (defined by libssh2) */ 448 | #define LIBSSH2_ERROR_NONE 0 449 | 450 | /* The library once used -1 as a generic error return value on numerous places 451 | through the code, which subsequently was converted to 452 | LIBSSH2_ERROR_SOCKET_NONE uses over time. As this is a generic error code, 453 | the goal is to never ever return this code but instead make sure that a 454 | more accurate and descriptive error code is used. */ 455 | #define LIBSSH2_ERROR_SOCKET_NONE -1 456 | 457 | #define LIBSSH2_ERROR_BANNER_RECV -2 458 | #define LIBSSH2_ERROR_BANNER_SEND -3 459 | #define LIBSSH2_ERROR_INVALID_MAC -4 460 | #define LIBSSH2_ERROR_KEX_FAILURE -5 461 | #define LIBSSH2_ERROR_ALLOC -6 462 | #define LIBSSH2_ERROR_SOCKET_SEND -7 463 | #define LIBSSH2_ERROR_KEY_EXCHANGE_FAILURE -8 464 | #define LIBSSH2_ERROR_TIMEOUT -9 465 | #define LIBSSH2_ERROR_HOSTKEY_INIT -10 466 | #define LIBSSH2_ERROR_HOSTKEY_SIGN -11 467 | #define LIBSSH2_ERROR_DECRYPT -12 468 | #define LIBSSH2_ERROR_SOCKET_DISCONNECT -13 469 | #define LIBSSH2_ERROR_PROTO -14 470 | #define LIBSSH2_ERROR_PASSWORD_EXPIRED -15 471 | #define LIBSSH2_ERROR_FILE -16 472 | #define LIBSSH2_ERROR_METHOD_NONE -17 473 | #define LIBSSH2_ERROR_AUTHENTICATION_FAILED -18 474 | #define LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED \ 475 | LIBSSH2_ERROR_AUTHENTICATION_FAILED 476 | #define LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED -19 477 | #define LIBSSH2_ERROR_CHANNEL_OUTOFORDER -20 478 | #define LIBSSH2_ERROR_CHANNEL_FAILURE -21 479 | #define LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED -22 480 | #define LIBSSH2_ERROR_CHANNEL_UNKNOWN -23 481 | #define LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED -24 482 | #define LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED -25 483 | #define LIBSSH2_ERROR_CHANNEL_CLOSED -26 484 | #define LIBSSH2_ERROR_CHANNEL_EOF_SENT -27 485 | #define LIBSSH2_ERROR_SCP_PROTOCOL -28 486 | #define LIBSSH2_ERROR_ZLIB -29 487 | #define LIBSSH2_ERROR_SOCKET_TIMEOUT -30 488 | #define LIBSSH2_ERROR_SFTP_PROTOCOL -31 489 | #define LIBSSH2_ERROR_REQUEST_DENIED -32 490 | #define LIBSSH2_ERROR_METHOD_NOT_SUPPORTED -33 491 | #define LIBSSH2_ERROR_INVAL -34 492 | #define LIBSSH2_ERROR_INVALID_POLL_TYPE -35 493 | #define LIBSSH2_ERROR_PUBLICKEY_PROTOCOL -36 494 | #define LIBSSH2_ERROR_EAGAIN -37 495 | #define LIBSSH2_ERROR_BUFFER_TOO_SMALL -38 496 | #define LIBSSH2_ERROR_BAD_USE -39 497 | #define LIBSSH2_ERROR_COMPRESS -40 498 | #define LIBSSH2_ERROR_OUT_OF_BOUNDARY -41 499 | #define LIBSSH2_ERROR_AGENT_PROTOCOL -42 500 | #define LIBSSH2_ERROR_SOCKET_RECV -43 501 | #define LIBSSH2_ERROR_ENCRYPT -44 502 | #define LIBSSH2_ERROR_BAD_SOCKET -45 503 | #define LIBSSH2_ERROR_KNOWN_HOSTS -46 504 | #define LIBSSH2_ERROR_CHANNEL_WINDOW_FULL -47 505 | #define LIBSSH2_ERROR_KEYFILE_AUTH_FAILED -48 506 | 507 | /* this is a define to provide the old (<= 1.2.7) name */ 508 | #define LIBSSH2_ERROR_BANNER_NONE LIBSSH2_ERROR_BANNER_RECV 509 | 510 | /* Global API */ 511 | #define LIBSSH2_INIT_NO_CRYPTO 0x0001 512 | 513 | /* 514 | * libssh2_init() 515 | * 516 | * Initialize the libssh2 functions. This typically initialize the 517 | * crypto library. It uses a global state, and is not thread safe -- 518 | * you must make sure this function is not called concurrently. 519 | * 520 | * Flags can be: 521 | * 0: Normal initialize 522 | * LIBSSH2_INIT_NO_CRYPTO: Do not initialize the crypto library (ie. 523 | * OPENSSL_add_cipher_algoritms() for OpenSSL 524 | * 525 | * Returns 0 if succeeded, or a negative value for error. 526 | */ 527 | LIBSSH2_API int libssh2_init(int flags); 528 | 529 | /* 530 | * libssh2_exit() 531 | * 532 | * Exit the libssh2 functions and free's all memory used internal. 533 | */ 534 | LIBSSH2_API void libssh2_exit(void); 535 | 536 | /* 537 | * libssh2_free() 538 | * 539 | * Deallocate memory allocated by earlier call to libssh2 functions. 540 | */ 541 | LIBSSH2_API void libssh2_free(LIBSSH2_SESSION *session, void *ptr); 542 | 543 | /* 544 | * libssh2_session_supported_algs() 545 | * 546 | * Fills algs with a list of supported acryptographic algorithms. Returns a 547 | * non-negative number (number of supported algorithms) on success or a 548 | * negative number (an eror code) on failure. 549 | * 550 | * NOTE: on success, algs must be deallocated (by calling libssh2_free) when 551 | * not needed anymore 552 | */ 553 | LIBSSH2_API int libssh2_session_supported_algs(LIBSSH2_SESSION* session, 554 | int method_type, 555 | const char ***algs); 556 | 557 | /* Session API */ 558 | LIBSSH2_API LIBSSH2_SESSION * 559 | libssh2_session_init_ex(LIBSSH2_ALLOC_FUNC((*my_alloc)), 560 | LIBSSH2_FREE_FUNC((*my_free)), 561 | LIBSSH2_REALLOC_FUNC((*my_realloc)), void *abstract); 562 | #define libssh2_session_init() libssh2_session_init_ex(NULL, NULL, NULL, NULL) 563 | 564 | LIBSSH2_API void **libssh2_session_abstract(LIBSSH2_SESSION *session); 565 | 566 | LIBSSH2_API void *libssh2_session_callback_set(LIBSSH2_SESSION *session, 567 | int cbtype, void *callback); 568 | LIBSSH2_API int libssh2_session_banner_set(LIBSSH2_SESSION *session, 569 | const char *banner); 570 | LIBSSH2_API int libssh2_banner_set(LIBSSH2_SESSION *session, 571 | const char *banner); 572 | 573 | LIBSSH2_API int libssh2_session_startup(LIBSSH2_SESSION *session, int sock); 574 | LIBSSH2_API int libssh2_session_handshake(LIBSSH2_SESSION *session, 575 | libssh2_socket_t sock); 576 | LIBSSH2_API int libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, 577 | int reason, 578 | const char *description, 579 | const char *lang); 580 | #define libssh2_session_disconnect(session, description) \ 581 | libssh2_session_disconnect_ex((session), SSH_DISCONNECT_BY_APPLICATION, \ 582 | (description), "") 583 | 584 | LIBSSH2_API int libssh2_session_free(LIBSSH2_SESSION *session); 585 | 586 | LIBSSH2_API const char *libssh2_hostkey_hash(LIBSSH2_SESSION *session, 587 | int hash_type); 588 | 589 | LIBSSH2_API const char *libssh2_session_hostkey(LIBSSH2_SESSION *session, 590 | size_t *len, int *type); 591 | 592 | LIBSSH2_API int libssh2_session_method_pref(LIBSSH2_SESSION *session, 593 | int method_type, 594 | const char *prefs); 595 | LIBSSH2_API const char *libssh2_session_methods(LIBSSH2_SESSION *session, 596 | int method_type); 597 | LIBSSH2_API int libssh2_session_last_error(LIBSSH2_SESSION *session, 598 | char **errmsg, 599 | int *errmsg_len, int want_buf); 600 | LIBSSH2_API int libssh2_session_last_errno(LIBSSH2_SESSION *session); 601 | LIBSSH2_API int libssh2_session_set_last_error(LIBSSH2_SESSION* session, 602 | int errcode, 603 | const char *errmsg); 604 | LIBSSH2_API int libssh2_session_block_directions(LIBSSH2_SESSION *session); 605 | 606 | LIBSSH2_API int libssh2_session_flag(LIBSSH2_SESSION *session, int flag, 607 | int value); 608 | LIBSSH2_API const char *libssh2_session_banner_get(LIBSSH2_SESSION *session); 609 | 610 | /* Userauth API */ 611 | LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, 612 | const char *username, 613 | unsigned int username_len); 614 | LIBSSH2_API int libssh2_userauth_authenticated(LIBSSH2_SESSION *session); 615 | 616 | LIBSSH2_API int 617 | libssh2_userauth_password_ex(LIBSSH2_SESSION *session, 618 | const char *username, 619 | unsigned int username_len, 620 | const char *password, 621 | unsigned int password_len, 622 | LIBSSH2_PASSWD_CHANGEREQ_FUNC 623 | ((*passwd_change_cb))); 624 | 625 | #define libssh2_userauth_password(session, username, password) \ 626 | libssh2_userauth_password_ex((session), (username), \ 627 | (unsigned int)strlen(username), \ 628 | (password), (unsigned int)strlen(password), NULL) 629 | 630 | LIBSSH2_API int 631 | libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, 632 | const char *username, 633 | unsigned int username_len, 634 | const char *publickey, 635 | const char *privatekey, 636 | const char *passphrase); 637 | 638 | #define libssh2_userauth_publickey_fromfile(session, username, publickey, \ 639 | privatekey, passphrase) \ 640 | libssh2_userauth_publickey_fromfile_ex((session), (username), \ 641 | (unsigned int)strlen(username), \ 642 | (publickey), \ 643 | (privatekey), (passphrase)) 644 | 645 | LIBSSH2_API int 646 | libssh2_userauth_publickey(LIBSSH2_SESSION *session, 647 | const char *username, 648 | const unsigned char *pubkeydata, 649 | size_t pubkeydata_len, 650 | LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC 651 | ((*sign_callback)), 652 | void **abstract); 653 | 654 | LIBSSH2_API int 655 | libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session, 656 | const char *username, 657 | unsigned int username_len, 658 | const char *publickey, 659 | const char *privatekey, 660 | const char *passphrase, 661 | const char *hostname, 662 | unsigned int hostname_len, 663 | const char *local_username, 664 | unsigned int local_username_len); 665 | 666 | #define libssh2_userauth_hostbased_fromfile(session, username, publickey, \ 667 | privatekey, passphrase, hostname) \ 668 | libssh2_userauth_hostbased_fromfile_ex((session), (username), \ 669 | (unsigned int)strlen(username), \ 670 | (publickey), \ 671 | (privatekey), (passphrase), \ 672 | (hostname), \ 673 | (unsigned int)strlen(hostname), \ 674 | (username), \ 675 | (unsigned int)strlen(username)) 676 | 677 | LIBSSH2_API int 678 | libssh2_userauth_publickey_frommemory(LIBSSH2_SESSION *session, 679 | const char *username, 680 | size_t username_len, 681 | const char *publickeyfiledata, 682 | size_t publickeyfiledata_len, 683 | const char *privatekeyfiledata, 684 | size_t privatekeyfiledata_len, 685 | const char *passphrase); 686 | 687 | /* 688 | * response_callback is provided with filled by library prompts array, 689 | * but client must allocate and fill individual responses. Responses 690 | * array is already allocated. Responses data will be freed by libssh2 691 | * after callback return, but before subsequent callback invokation. 692 | */ 693 | LIBSSH2_API int 694 | libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION* session, 695 | const char *username, 696 | unsigned int username_len, 697 | LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC( 698 | (*response_callback))); 699 | 700 | #define libssh2_userauth_keyboard_interactive(session, username, \ 701 | response_callback) \ 702 | libssh2_userauth_keyboard_interactive_ex((session), (username), \ 703 | (unsigned int)strlen(username), \ 704 | (response_callback)) 705 | 706 | LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds, 707 | long timeout); 708 | 709 | /* Channel API */ 710 | #define LIBSSH2_CHANNEL_WINDOW_DEFAULT (2*1024*1024) 711 | #define LIBSSH2_CHANNEL_PACKET_DEFAULT 32768 712 | #define LIBSSH2_CHANNEL_MINADJUST 1024 713 | 714 | /* Extended Data Handling */ 715 | #define LIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL 0 716 | #define LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE 1 717 | #define LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE 2 718 | 719 | #define SSH_EXTENDED_DATA_STDERR 1 720 | 721 | /* Returned by any function that would block during a read/write opperation */ 722 | #define LIBSSH2CHANNEL_EAGAIN LIBSSH2_ERROR_EAGAIN 723 | 724 | LIBSSH2_API LIBSSH2_CHANNEL * 725 | libssh2_channel_open_ex(LIBSSH2_SESSION *session, const char *channel_type, 726 | unsigned int channel_type_len, 727 | unsigned int window_size, unsigned int packet_size, 728 | const char *message, unsigned int message_len); 729 | 730 | #define libssh2_channel_open_session(session) \ 731 | libssh2_channel_open_ex((session), "session", sizeof("session") - 1, \ 732 | LIBSSH2_CHANNEL_WINDOW_DEFAULT, \ 733 | LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0) 734 | 735 | LIBSSH2_API LIBSSH2_CHANNEL * 736 | libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *session, const char *host, 737 | int port, const char *shost, int sport); 738 | #define libssh2_channel_direct_tcpip(session, host, port) \ 739 | libssh2_channel_direct_tcpip_ex((session), (host), (port), "127.0.0.1", 22) 740 | 741 | LIBSSH2_API LIBSSH2_LISTENER * 742 | libssh2_channel_forward_listen_ex(LIBSSH2_SESSION *session, const char *host, 743 | int port, int *bound_port, 744 | int queue_maxsize); 745 | #define libssh2_channel_forward_listen(session, port) \ 746 | libssh2_channel_forward_listen_ex((session), NULL, (port), NULL, 16) 747 | 748 | LIBSSH2_API int libssh2_channel_forward_cancel(LIBSSH2_LISTENER *listener); 749 | 750 | LIBSSH2_API LIBSSH2_CHANNEL * 751 | libssh2_channel_forward_accept(LIBSSH2_LISTENER *listener); 752 | 753 | LIBSSH2_API int libssh2_channel_setenv_ex(LIBSSH2_CHANNEL *channel, 754 | const char *varname, 755 | unsigned int varname_len, 756 | const char *value, 757 | unsigned int value_len); 758 | 759 | #define libssh2_channel_setenv(channel, varname, value) \ 760 | libssh2_channel_setenv_ex((channel), (varname), \ 761 | (unsigned int)strlen(varname), (value), \ 762 | (unsigned int)strlen(value)) 763 | 764 | LIBSSH2_API int libssh2_channel_request_pty_ex(LIBSSH2_CHANNEL *channel, 765 | const char *term, 766 | unsigned int term_len, 767 | const char *modes, 768 | unsigned int modes_len, 769 | int width, int height, 770 | int width_px, int height_px); 771 | #define libssh2_channel_request_pty(channel, term) \ 772 | libssh2_channel_request_pty_ex((channel), (term), \ 773 | (unsigned int)strlen(term), \ 774 | NULL, 0, \ 775 | LIBSSH2_TERM_WIDTH, \ 776 | LIBSSH2_TERM_HEIGHT, \ 777 | LIBSSH2_TERM_WIDTH_PX, \ 778 | LIBSSH2_TERM_HEIGHT_PX) 779 | 780 | LIBSSH2_API int libssh2_channel_request_pty_size_ex(LIBSSH2_CHANNEL *channel, 781 | int width, int height, 782 | int width_px, 783 | int height_px); 784 | #define libssh2_channel_request_pty_size(channel, width, height) \ 785 | libssh2_channel_request_pty_size_ex((channel), (width), (height), 0, 0) 786 | 787 | LIBSSH2_API int libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL *channel, 788 | int single_connection, 789 | const char *auth_proto, 790 | const char *auth_cookie, 791 | int screen_number); 792 | #define libssh2_channel_x11_req(channel, screen_number) \ 793 | libssh2_channel_x11_req_ex((channel), 0, NULL, NULL, (screen_number)) 794 | 795 | LIBSSH2_API int libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, 796 | const char *request, 797 | unsigned int request_len, 798 | const char *message, 799 | unsigned int message_len); 800 | #define libssh2_channel_shell(channel) \ 801 | libssh2_channel_process_startup((channel), "shell", sizeof("shell") - 1, \ 802 | NULL, 0) 803 | #define libssh2_channel_exec(channel, command) \ 804 | libssh2_channel_process_startup((channel), "exec", sizeof("exec") - 1, \ 805 | (command), (unsigned int)strlen(command)) 806 | #define libssh2_channel_subsystem(channel, subsystem) \ 807 | libssh2_channel_process_startup((channel), "subsystem", \ 808 | sizeof("subsystem") - 1, (subsystem), \ 809 | (unsigned int)strlen(subsystem)) 810 | 811 | LIBSSH2_API ssize_t libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, 812 | int stream_id, char *buf, 813 | size_t buflen); 814 | #define libssh2_channel_read(channel, buf, buflen) \ 815 | libssh2_channel_read_ex((channel), 0, (buf), (buflen)) 816 | #define libssh2_channel_read_stderr(channel, buf, buflen) \ 817 | libssh2_channel_read_ex((channel), SSH_EXTENDED_DATA_STDERR, (buf), (buflen)) 818 | 819 | LIBSSH2_API int libssh2_poll_channel_read(LIBSSH2_CHANNEL *channel, 820 | int extended); 821 | 822 | LIBSSH2_API unsigned long 823 | libssh2_channel_window_read_ex(LIBSSH2_CHANNEL *channel, 824 | unsigned long *read_avail, 825 | unsigned long *window_size_initial); 826 | #define libssh2_channel_window_read(channel) \ 827 | libssh2_channel_window_read_ex((channel), NULL, NULL) 828 | 829 | /* libssh2_channel_receive_window_adjust is DEPRECATED, do not use! */ 830 | LIBSSH2_API unsigned long 831 | libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL *channel, 832 | unsigned long adjustment, 833 | unsigned char force); 834 | 835 | LIBSSH2_API int 836 | libssh2_channel_receive_window_adjust2(LIBSSH2_CHANNEL *channel, 837 | unsigned long adjustment, 838 | unsigned char force, 839 | unsigned int *storewindow); 840 | 841 | LIBSSH2_API ssize_t libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel, 842 | int stream_id, const char *buf, 843 | size_t buflen); 844 | 845 | #define libssh2_channel_write(channel, buf, buflen) \ 846 | libssh2_channel_write_ex((channel), 0, (buf), (buflen)) 847 | #define libssh2_channel_write_stderr(channel, buf, buflen) \ 848 | libssh2_channel_write_ex((channel), SSH_EXTENDED_DATA_STDERR, \ 849 | (buf), (buflen)) 850 | 851 | LIBSSH2_API unsigned long 852 | libssh2_channel_window_write_ex(LIBSSH2_CHANNEL *channel, 853 | unsigned long *window_size_initial); 854 | #define libssh2_channel_window_write(channel) \ 855 | libssh2_channel_window_write_ex((channel), NULL) 856 | 857 | LIBSSH2_API void libssh2_session_set_blocking(LIBSSH2_SESSION* session, 858 | int blocking); 859 | LIBSSH2_API int libssh2_session_get_blocking(LIBSSH2_SESSION* session); 860 | 861 | LIBSSH2_API void libssh2_channel_set_blocking(LIBSSH2_CHANNEL *channel, 862 | int blocking); 863 | 864 | LIBSSH2_API void libssh2_session_set_timeout(LIBSSH2_SESSION* session, 865 | long timeout); 866 | LIBSSH2_API long libssh2_session_get_timeout(LIBSSH2_SESSION* session); 867 | 868 | /* libssh2_channel_handle_extended_data is DEPRECATED, do not use! */ 869 | LIBSSH2_API void libssh2_channel_handle_extended_data(LIBSSH2_CHANNEL *channel, 870 | int ignore_mode); 871 | LIBSSH2_API int libssh2_channel_handle_extended_data2(LIBSSH2_CHANNEL *channel, 872 | int ignore_mode); 873 | 874 | /* libssh2_channel_ignore_extended_data() is defined below for BC with version 875 | * 0.1 876 | * 877 | * Future uses should use libssh2_channel_handle_extended_data() directly if 878 | * LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE is passed, extended data will be read 879 | * (FIFO) from the standard data channel 880 | */ 881 | /* DEPRECATED */ 882 | #define libssh2_channel_ignore_extended_data(channel, ignore) \ 883 | libssh2_channel_handle_extended_data((channel), \ 884 | (ignore) ? \ 885 | LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE : \ 886 | LIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL) 887 | 888 | #define LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA -1 889 | #define LIBSSH2_CHANNEL_FLUSH_ALL -2 890 | LIBSSH2_API int libssh2_channel_flush_ex(LIBSSH2_CHANNEL *channel, 891 | int streamid); 892 | #define libssh2_channel_flush(channel) libssh2_channel_flush_ex((channel), 0) 893 | #define libssh2_channel_flush_stderr(channel) \ 894 | libssh2_channel_flush_ex((channel), SSH_EXTENDED_DATA_STDERR) 895 | 896 | LIBSSH2_API int libssh2_channel_get_exit_status(LIBSSH2_CHANNEL* channel); 897 | LIBSSH2_API int libssh2_channel_get_exit_signal(LIBSSH2_CHANNEL* channel, 898 | char **exitsignal, 899 | size_t *exitsignal_len, 900 | char **errmsg, 901 | size_t *errmsg_len, 902 | char **langtag, 903 | size_t *langtag_len); 904 | LIBSSH2_API int libssh2_channel_send_eof(LIBSSH2_CHANNEL *channel); 905 | LIBSSH2_API int libssh2_channel_eof(LIBSSH2_CHANNEL *channel); 906 | LIBSSH2_API int libssh2_channel_wait_eof(LIBSSH2_CHANNEL *channel); 907 | LIBSSH2_API int libssh2_channel_close(LIBSSH2_CHANNEL *channel); 908 | LIBSSH2_API int libssh2_channel_wait_closed(LIBSSH2_CHANNEL *channel); 909 | LIBSSH2_API int libssh2_channel_free(LIBSSH2_CHANNEL *channel); 910 | 911 | /* libssh2_scp_recv is DEPRECATED, do not use! */ 912 | LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, 913 | const char *path, 914 | struct stat *sb); 915 | /* Use libssh2_scp_recv2 for large (> 2GB) file support on windows */ 916 | LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv2(LIBSSH2_SESSION *session, 917 | const char *path, 918 | libssh2_struct_stat *sb); 919 | LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, 920 | const char *path, int mode, 921 | size_t size, long mtime, 922 | long atime); 923 | LIBSSH2_API LIBSSH2_CHANNEL * 924 | libssh2_scp_send64(LIBSSH2_SESSION *session, const char *path, int mode, 925 | libssh2_int64_t size, time_t mtime, time_t atime); 926 | 927 | #define libssh2_scp_send(session, path, mode, size) \ 928 | libssh2_scp_send_ex((session), (path), (mode), (size), 0, 0) 929 | 930 | LIBSSH2_API int libssh2_base64_decode(LIBSSH2_SESSION *session, char **dest, 931 | unsigned int *dest_len, 932 | const char *src, unsigned int src_len); 933 | 934 | LIBSSH2_API 935 | const char *libssh2_version(int req_version_num); 936 | 937 | #define HAVE_LIBSSH2_KNOWNHOST_API 0x010101 /* since 1.1.1 */ 938 | #define HAVE_LIBSSH2_VERSION_API 0x010100 /* libssh2_version since 1.1 */ 939 | 940 | struct libssh2_knownhost { 941 | unsigned int magic; /* magic stored by the library */ 942 | void *node; /* handle to the internal representation of this host */ 943 | char *name; /* this is NULL if no plain text host name exists */ 944 | char *key; /* key in base64/printable format */ 945 | int typemask; 946 | }; 947 | 948 | /* 949 | * libssh2_knownhost_init 950 | * 951 | * Init a collection of known hosts. Returns the pointer to a collection. 952 | * 953 | */ 954 | LIBSSH2_API LIBSSH2_KNOWNHOSTS * 955 | libssh2_knownhost_init(LIBSSH2_SESSION *session); 956 | 957 | /* 958 | * libssh2_knownhost_add 959 | * 960 | * Add a host and its associated key to the collection of known hosts. 961 | * 962 | * The 'type' argument specifies on what format the given host and keys are: 963 | * 964 | * plain - ascii "hostname.domain.tld" 965 | * sha1 - SHA1( ) base64-encoded! 966 | * custom - another hash 967 | * 968 | * If 'sha1' is selected as type, the salt must be provided to the salt 969 | * argument. This too base64 encoded. 970 | * 971 | * The SHA-1 hash is what OpenSSH can be told to use in known_hosts files. If 972 | * a custom type is used, salt is ignored and you must provide the host 973 | * pre-hashed when checking for it in the libssh2_knownhost_check() function. 974 | * 975 | * The keylen parameter may be omitted (zero) if the key is provided as a 976 | * NULL-terminated base64-encoded string. 977 | */ 978 | 979 | /* host format (2 bits) */ 980 | #define LIBSSH2_KNOWNHOST_TYPE_MASK 0xffff 981 | #define LIBSSH2_KNOWNHOST_TYPE_PLAIN 1 982 | #define LIBSSH2_KNOWNHOST_TYPE_SHA1 2 /* always base64 encoded */ 983 | #define LIBSSH2_KNOWNHOST_TYPE_CUSTOM 3 984 | 985 | /* key format (2 bits) */ 986 | #define LIBSSH2_KNOWNHOST_KEYENC_MASK (3<<16) 987 | #define LIBSSH2_KNOWNHOST_KEYENC_RAW (1<<16) 988 | #define LIBSSH2_KNOWNHOST_KEYENC_BASE64 (2<<16) 989 | 990 | /* type of key (3 bits) */ 991 | #define LIBSSH2_KNOWNHOST_KEY_MASK (15<<18) 992 | #define LIBSSH2_KNOWNHOST_KEY_SHIFT 18 993 | #define LIBSSH2_KNOWNHOST_KEY_RSA1 (1<<18) 994 | #define LIBSSH2_KNOWNHOST_KEY_SSHRSA (2<<18) 995 | #define LIBSSH2_KNOWNHOST_KEY_SSHDSS (3<<18) 996 | #define LIBSSH2_KNOWNHOST_KEY_ECDSA_256 (4<<18) 997 | #define LIBSSH2_KNOWNHOST_KEY_ECDSA_384 (5<<18) 998 | #define LIBSSH2_KNOWNHOST_KEY_ECDSA_521 (6<<18) 999 | #define LIBSSH2_KNOWNHOST_KEY_ED25519 (7<<18) 1000 | #define LIBSSH2_KNOWNHOST_KEY_UNKNOWN (15<<18) 1001 | 1002 | LIBSSH2_API int 1003 | libssh2_knownhost_add(LIBSSH2_KNOWNHOSTS *hosts, 1004 | const char *host, 1005 | const char *salt, 1006 | const char *key, size_t keylen, int typemask, 1007 | struct libssh2_knownhost **store); 1008 | 1009 | /* 1010 | * libssh2_knownhost_addc 1011 | * 1012 | * Add a host and its associated key to the collection of known hosts. 1013 | * 1014 | * Takes a comment argument that may be NULL. A NULL comment indicates 1015 | * there is no comment and the entry will end directly after the key 1016 | * when written out to a file. An empty string "" comment will indicate an 1017 | * empty comment which will cause a single space to be written after the key. 1018 | * 1019 | * The 'type' argument specifies on what format the given host and keys are: 1020 | * 1021 | * plain - ascii "hostname.domain.tld" 1022 | * sha1 - SHA1( ) base64-encoded! 1023 | * custom - another hash 1024 | * 1025 | * If 'sha1' is selected as type, the salt must be provided to the salt 1026 | * argument. This too base64 encoded. 1027 | * 1028 | * The SHA-1 hash is what OpenSSH can be told to use in known_hosts files. If 1029 | * a custom type is used, salt is ignored and you must provide the host 1030 | * pre-hashed when checking for it in the libssh2_knownhost_check() function. 1031 | * 1032 | * The keylen parameter may be omitted (zero) if the key is provided as a 1033 | * NULL-terminated base64-encoded string. 1034 | */ 1035 | 1036 | LIBSSH2_API int 1037 | libssh2_knownhost_addc(LIBSSH2_KNOWNHOSTS *hosts, 1038 | const char *host, 1039 | const char *salt, 1040 | const char *key, size_t keylen, 1041 | const char *comment, size_t commentlen, int typemask, 1042 | struct libssh2_knownhost **store); 1043 | 1044 | /* 1045 | * libssh2_knownhost_check 1046 | * 1047 | * Check a host and its associated key against the collection of known hosts. 1048 | * 1049 | * The type is the type/format of the given host name. 1050 | * 1051 | * plain - ascii "hostname.domain.tld" 1052 | * custom - prehashed base64 encoded. Note that this cannot use any salts. 1053 | * 1054 | * 1055 | * 'knownhost' may be set to NULL if you don't care about that info. 1056 | * 1057 | * Returns: 1058 | * 1059 | * LIBSSH2_KNOWNHOST_CHECK_* values, see below 1060 | * 1061 | */ 1062 | 1063 | #define LIBSSH2_KNOWNHOST_CHECK_MATCH 0 1064 | #define LIBSSH2_KNOWNHOST_CHECK_MISMATCH 1 1065 | #define LIBSSH2_KNOWNHOST_CHECK_NOTFOUND 2 1066 | #define LIBSSH2_KNOWNHOST_CHECK_FAILURE 3 1067 | 1068 | LIBSSH2_API int 1069 | libssh2_knownhost_check(LIBSSH2_KNOWNHOSTS *hosts, 1070 | const char *host, const char *key, size_t keylen, 1071 | int typemask, 1072 | struct libssh2_knownhost **knownhost); 1073 | 1074 | /* this function is identital to the above one, but also takes a port 1075 | argument that allows libssh2 to do a better check */ 1076 | LIBSSH2_API int 1077 | libssh2_knownhost_checkp(LIBSSH2_KNOWNHOSTS *hosts, 1078 | const char *host, int port, 1079 | const char *key, size_t keylen, 1080 | int typemask, 1081 | struct libssh2_knownhost **knownhost); 1082 | 1083 | /* 1084 | * libssh2_knownhost_del 1085 | * 1086 | * Remove a host from the collection of known hosts. The 'entry' struct is 1087 | * retrieved by a call to libssh2_knownhost_check(). 1088 | * 1089 | */ 1090 | LIBSSH2_API int 1091 | libssh2_knownhost_del(LIBSSH2_KNOWNHOSTS *hosts, 1092 | struct libssh2_knownhost *entry); 1093 | 1094 | /* 1095 | * libssh2_knownhost_free 1096 | * 1097 | * Free an entire collection of known hosts. 1098 | * 1099 | */ 1100 | LIBSSH2_API void 1101 | libssh2_knownhost_free(LIBSSH2_KNOWNHOSTS *hosts); 1102 | 1103 | /* 1104 | * libssh2_knownhost_readline() 1105 | * 1106 | * Pass in a line of a file of 'type'. It makes libssh2 read this line. 1107 | * 1108 | * LIBSSH2_KNOWNHOST_FILE_OPENSSH is the only supported type. 1109 | * 1110 | */ 1111 | LIBSSH2_API int 1112 | libssh2_knownhost_readline(LIBSSH2_KNOWNHOSTS *hosts, 1113 | const char *line, size_t len, int type); 1114 | 1115 | /* 1116 | * libssh2_knownhost_readfile 1117 | * 1118 | * Add hosts+key pairs from a given file. 1119 | * 1120 | * Returns a negative value for error or number of successfully added hosts. 1121 | * 1122 | * This implementation currently only knows one 'type' (openssh), all others 1123 | * are reserved for future use. 1124 | */ 1125 | 1126 | #define LIBSSH2_KNOWNHOST_FILE_OPENSSH 1 1127 | 1128 | LIBSSH2_API int 1129 | libssh2_knownhost_readfile(LIBSSH2_KNOWNHOSTS *hosts, 1130 | const char *filename, int type); 1131 | 1132 | /* 1133 | * libssh2_knownhost_writeline() 1134 | * 1135 | * Ask libssh2 to convert a known host to an output line for storage. 1136 | * 1137 | * Note that this function returns LIBSSH2_ERROR_BUFFER_TOO_SMALL if the given 1138 | * output buffer is too small to hold the desired output. 1139 | * 1140 | * This implementation currently only knows one 'type' (openssh), all others 1141 | * are reserved for future use. 1142 | * 1143 | */ 1144 | LIBSSH2_API int 1145 | libssh2_knownhost_writeline(LIBSSH2_KNOWNHOSTS *hosts, 1146 | struct libssh2_knownhost *known, 1147 | char *buffer, size_t buflen, 1148 | size_t *outlen, /* the amount of written data */ 1149 | int type); 1150 | 1151 | /* 1152 | * libssh2_knownhost_writefile 1153 | * 1154 | * Write hosts+key pairs to a given file. 1155 | * 1156 | * This implementation currently only knows one 'type' (openssh), all others 1157 | * are reserved for future use. 1158 | */ 1159 | 1160 | LIBSSH2_API int 1161 | libssh2_knownhost_writefile(LIBSSH2_KNOWNHOSTS *hosts, 1162 | const char *filename, int type); 1163 | 1164 | /* 1165 | * libssh2_knownhost_get() 1166 | * 1167 | * Traverse the internal list of known hosts. Pass NULL to 'prev' to get 1168 | * the first one. Or pass a poiner to the previously returned one to get the 1169 | * next. 1170 | * 1171 | * Returns: 1172 | * 0 if a fine host was stored in 'store' 1173 | * 1 if end of hosts 1174 | * [negative] on errors 1175 | */ 1176 | LIBSSH2_API int 1177 | libssh2_knownhost_get(LIBSSH2_KNOWNHOSTS *hosts, 1178 | struct libssh2_knownhost **store, 1179 | struct libssh2_knownhost *prev); 1180 | 1181 | #define HAVE_LIBSSH2_AGENT_API 0x010202 /* since 1.2.2 */ 1182 | 1183 | struct libssh2_agent_publickey { 1184 | unsigned int magic; /* magic stored by the library */ 1185 | void *node; /* handle to the internal representation of key */ 1186 | unsigned char *blob; /* public key blob */ 1187 | size_t blob_len; /* length of the public key blob */ 1188 | char *comment; /* comment in printable format */ 1189 | }; 1190 | 1191 | /* 1192 | * libssh2_agent_init 1193 | * 1194 | * Init an ssh-agent handle. Returns the pointer to the handle. 1195 | * 1196 | */ 1197 | LIBSSH2_API LIBSSH2_AGENT * 1198 | libssh2_agent_init(LIBSSH2_SESSION *session); 1199 | 1200 | /* 1201 | * libssh2_agent_connect() 1202 | * 1203 | * Connect to an ssh-agent. 1204 | * 1205 | * Returns 0 if succeeded, or a negative value for error. 1206 | */ 1207 | LIBSSH2_API int 1208 | libssh2_agent_connect(LIBSSH2_AGENT *agent); 1209 | 1210 | /* 1211 | * libssh2_agent_list_identities() 1212 | * 1213 | * Request an ssh-agent to list identities. 1214 | * 1215 | * Returns 0 if succeeded, or a negative value for error. 1216 | */ 1217 | LIBSSH2_API int 1218 | libssh2_agent_list_identities(LIBSSH2_AGENT *agent); 1219 | 1220 | /* 1221 | * libssh2_agent_get_identity() 1222 | * 1223 | * Traverse the internal list of public keys. Pass NULL to 'prev' to get 1224 | * the first one. Or pass a poiner to the previously returned one to get the 1225 | * next. 1226 | * 1227 | * Returns: 1228 | * 0 if a fine public key was stored in 'store' 1229 | * 1 if end of public keys 1230 | * [negative] on errors 1231 | */ 1232 | LIBSSH2_API int 1233 | libssh2_agent_get_identity(LIBSSH2_AGENT *agent, 1234 | struct libssh2_agent_publickey **store, 1235 | struct libssh2_agent_publickey *prev); 1236 | 1237 | /* 1238 | * libssh2_agent_userauth() 1239 | * 1240 | * Do publickey user authentication with the help of ssh-agent. 1241 | * 1242 | * Returns 0 if succeeded, or a negative value for error. 1243 | */ 1244 | LIBSSH2_API int 1245 | libssh2_agent_userauth(LIBSSH2_AGENT *agent, 1246 | const char *username, 1247 | struct libssh2_agent_publickey *identity); 1248 | 1249 | /* 1250 | * libssh2_agent_disconnect() 1251 | * 1252 | * Close a connection to an ssh-agent. 1253 | * 1254 | * Returns 0 if succeeded, or a negative value for error. 1255 | */ 1256 | LIBSSH2_API int 1257 | libssh2_agent_disconnect(LIBSSH2_AGENT *agent); 1258 | 1259 | /* 1260 | * libssh2_agent_free() 1261 | * 1262 | * Free an ssh-agent handle. This function also frees the internal 1263 | * collection of public keys. 1264 | */ 1265 | LIBSSH2_API void 1266 | libssh2_agent_free(LIBSSH2_AGENT *agent); 1267 | 1268 | /* 1269 | * libssh2_agent_set_identity_path() 1270 | * 1271 | * Allows a custom agent identity socket path beyond SSH_AUTH_SOCK env 1272 | * 1273 | */ 1274 | LIBSSH2_API void 1275 | libssh2_agent_set_identity_path(LIBSSH2_AGENT *agent, 1276 | const char *path); 1277 | 1278 | /* 1279 | * libssh2_agent_get_identity_path() 1280 | * 1281 | * Returns the custom agent identity socket path if set 1282 | * 1283 | */ 1284 | LIBSSH2_API const char * 1285 | libssh2_agent_get_identity_path(LIBSSH2_AGENT *agent); 1286 | 1287 | /* 1288 | * libssh2_keepalive_config() 1289 | * 1290 | * Set how often keepalive messages should be sent. WANT_REPLY 1291 | * indicates whether the keepalive messages should request a response 1292 | * from the server. INTERVAL is number of seconds that can pass 1293 | * without any I/O, use 0 (the default) to disable keepalives. To 1294 | * avoid some busy-loop corner-cases, if you specify an interval of 1 1295 | * it will be treated as 2. 1296 | * 1297 | * Note that non-blocking applications are responsible for sending the 1298 | * keepalive messages using libssh2_keepalive_send(). 1299 | */ 1300 | LIBSSH2_API void libssh2_keepalive_config(LIBSSH2_SESSION *session, 1301 | int want_reply, 1302 | unsigned interval); 1303 | 1304 | /* 1305 | * libssh2_keepalive_send() 1306 | * 1307 | * Send a keepalive message if needed. SECONDS_TO_NEXT indicates how 1308 | * many seconds you can sleep after this call before you need to call 1309 | * it again. Returns 0 on success, or LIBSSH2_ERROR_SOCKET_SEND on 1310 | * I/O errors. 1311 | */ 1312 | LIBSSH2_API int libssh2_keepalive_send(LIBSSH2_SESSION *session, 1313 | int *seconds_to_next); 1314 | 1315 | /* NOTE NOTE NOTE 1316 | libssh2_trace() has no function in builds that aren't built with debug 1317 | enabled 1318 | */ 1319 | LIBSSH2_API int libssh2_trace(LIBSSH2_SESSION *session, int bitmask); 1320 | #define LIBSSH2_TRACE_TRANS (1<<1) 1321 | #define LIBSSH2_TRACE_KEX (1<<2) 1322 | #define LIBSSH2_TRACE_AUTH (1<<3) 1323 | #define LIBSSH2_TRACE_CONN (1<<4) 1324 | #define LIBSSH2_TRACE_SCP (1<<5) 1325 | #define LIBSSH2_TRACE_SFTP (1<<6) 1326 | #define LIBSSH2_TRACE_ERROR (1<<7) 1327 | #define LIBSSH2_TRACE_PUBLICKEY (1<<8) 1328 | #define LIBSSH2_TRACE_SOCKET (1<<9) 1329 | 1330 | typedef void (*libssh2_trace_handler_func)(LIBSSH2_SESSION*, 1331 | void *, 1332 | const char *, 1333 | size_t); 1334 | LIBSSH2_API int libssh2_trace_sethandler(LIBSSH2_SESSION *session, 1335 | void *context, 1336 | libssh2_trace_handler_func callback); 1337 | 1338 | #ifdef __cplusplus 1339 | } /* extern "C" */ 1340 | #endif 1341 | 1342 | #endif /* !RC_INVOKED */ 1343 | 1344 | #endif /* LIBSSH2_H */ 1345 | -------------------------------------------------------------------------------- /Bin/C Headers/libssh2_publickey.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2004-2006, Sara Golemon 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, 5 | * with or without modification, are permitted provided 6 | * that the following conditions are met: 7 | * 8 | * Redistributions of source code must retain the above 9 | * copyright notice, this list of conditions and the 10 | * following disclaimer. 11 | * 12 | * Redistributions in binary form must reproduce the above 13 | * copyright notice, this list of conditions and the following 14 | * disclaimer in the documentation and/or other materials 15 | * provided with the distribution. 16 | * 17 | * Neither the name of the copyright holder nor the names 18 | * of any other contributors may be used to endorse or 19 | * promote products derived from this software without 20 | * specific prior written permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 23 | * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 24 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 27 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 29 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 30 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 32 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 33 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 34 | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 35 | * OF SUCH DAMAGE. 36 | */ 37 | 38 | /* Note: This include file is only needed for using the 39 | * publickey SUBSYSTEM which is not the same as publickey 40 | * authentication. For authentication you only need libssh2.h 41 | * 42 | * For more information on the publickey subsystem, 43 | * refer to IETF draft: secsh-publickey 44 | */ 45 | 46 | #ifndef LIBSSH2_PUBLICKEY_H 47 | #define LIBSSH2_PUBLICKEY_H 1 48 | 49 | #include "libssh2.h" 50 | 51 | typedef struct _LIBSSH2_PUBLICKEY LIBSSH2_PUBLICKEY; 52 | 53 | typedef struct _libssh2_publickey_attribute { 54 | const char *name; 55 | unsigned long name_len; 56 | const char *value; 57 | unsigned long value_len; 58 | char mandatory; 59 | } libssh2_publickey_attribute; 60 | 61 | typedef struct _libssh2_publickey_list { 62 | unsigned char *packet; /* For freeing */ 63 | 64 | const unsigned char *name; 65 | unsigned long name_len; 66 | const unsigned char *blob; 67 | unsigned long blob_len; 68 | unsigned long num_attrs; 69 | libssh2_publickey_attribute *attrs; /* free me */ 70 | } libssh2_publickey_list; 71 | 72 | /* Generally use the first macro here, but if both name and value are string 73 | literals, you can use _fast() to take advantage of preprocessing */ 74 | #define libssh2_publickey_attribute(name, value, mandatory) \ 75 | { (name), strlen(name), (value), strlen(value), (mandatory) }, 76 | #define libssh2_publickey_attribute_fast(name, value, mandatory) \ 77 | { (name), sizeof(name) - 1, (value), sizeof(value) - 1, (mandatory) }, 78 | 79 | #ifdef __cplusplus 80 | extern "C" { 81 | #endif 82 | 83 | /* Publickey Subsystem */ 84 | LIBSSH2_API LIBSSH2_PUBLICKEY * 85 | libssh2_publickey_init(LIBSSH2_SESSION *session); 86 | 87 | LIBSSH2_API int 88 | libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY *pkey, 89 | const unsigned char *name, 90 | unsigned long name_len, 91 | const unsigned char *blob, 92 | unsigned long blob_len, char overwrite, 93 | unsigned long num_attrs, 94 | const libssh2_publickey_attribute attrs[]); 95 | #define libssh2_publickey_add(pkey, name, blob, blob_len, overwrite, \ 96 | num_attrs, attrs) \ 97 | libssh2_publickey_add_ex((pkey), (name), strlen(name), (blob), (blob_len), \ 98 | (overwrite), (num_attrs), (attrs)) 99 | 100 | LIBSSH2_API int libssh2_publickey_remove_ex(LIBSSH2_PUBLICKEY *pkey, 101 | const unsigned char *name, 102 | unsigned long name_len, 103 | const unsigned char *blob, 104 | unsigned long blob_len); 105 | #define libssh2_publickey_remove(pkey, name, blob, blob_len) \ 106 | libssh2_publickey_remove_ex((pkey), (name), strlen(name), (blob), (blob_len)) 107 | 108 | LIBSSH2_API int 109 | libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY *pkey, 110 | unsigned long *num_keys, 111 | libssh2_publickey_list **pkey_list); 112 | LIBSSH2_API void 113 | libssh2_publickey_list_free(LIBSSH2_PUBLICKEY *pkey, 114 | libssh2_publickey_list *pkey_list); 115 | 116 | LIBSSH2_API int libssh2_publickey_shutdown(LIBSSH2_PUBLICKEY *pkey); 117 | 118 | #ifdef __cplusplus 119 | } /* extern "C" */ 120 | #endif 121 | 122 | #endif /* ifndef: LIBSSH2_PUBLICKEY_H */ 123 | -------------------------------------------------------------------------------- /Bin/C Headers/libssh2_sftp.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2004-2008, Sara Golemon 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, 5 | * with or without modification, are permitted provided 6 | * that the following conditions are met: 7 | * 8 | * Redistributions of source code must retain the above 9 | * copyright notice, this list of conditions and the 10 | * following disclaimer. 11 | * 12 | * Redistributions in binary form must reproduce the above 13 | * copyright notice, this list of conditions and the following 14 | * disclaimer in the documentation and/or other materials 15 | * provided with the distribution. 16 | * 17 | * Neither the name of the copyright holder nor the names 18 | * of any other contributors may be used to endorse or 19 | * promote products derived from this software without 20 | * specific prior written permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 23 | * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 24 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 27 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 29 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 30 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 32 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 33 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 34 | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 35 | * OF SUCH DAMAGE. 36 | */ 37 | 38 | #ifndef LIBSSH2_SFTP_H 39 | #define LIBSSH2_SFTP_H 1 40 | 41 | #include "libssh2.h" 42 | 43 | #ifndef WIN32 44 | #include 45 | #endif 46 | 47 | #ifdef __cplusplus 48 | extern "C" { 49 | #endif 50 | 51 | /* Note: Version 6 was documented at the time of writing 52 | * However it was marked as "DO NOT IMPLEMENT" due to pending changes 53 | * 54 | * Let's start with Version 3 (The version found in OpenSSH) and go from there 55 | */ 56 | #define LIBSSH2_SFTP_VERSION 3 57 | 58 | typedef struct _LIBSSH2_SFTP LIBSSH2_SFTP; 59 | typedef struct _LIBSSH2_SFTP_HANDLE LIBSSH2_SFTP_HANDLE; 60 | typedef struct _LIBSSH2_SFTP_ATTRIBUTES LIBSSH2_SFTP_ATTRIBUTES; 61 | typedef struct _LIBSSH2_SFTP_STATVFS LIBSSH2_SFTP_STATVFS; 62 | 63 | /* Flags for open_ex() */ 64 | #define LIBSSH2_SFTP_OPENFILE 0 65 | #define LIBSSH2_SFTP_OPENDIR 1 66 | 67 | /* Flags for rename_ex() */ 68 | #define LIBSSH2_SFTP_RENAME_OVERWRITE 0x00000001 69 | #define LIBSSH2_SFTP_RENAME_ATOMIC 0x00000002 70 | #define LIBSSH2_SFTP_RENAME_NATIVE 0x00000004 71 | 72 | /* Flags for stat_ex() */ 73 | #define LIBSSH2_SFTP_STAT 0 74 | #define LIBSSH2_SFTP_LSTAT 1 75 | #define LIBSSH2_SFTP_SETSTAT 2 76 | 77 | /* Flags for symlink_ex() */ 78 | #define LIBSSH2_SFTP_SYMLINK 0 79 | #define LIBSSH2_SFTP_READLINK 1 80 | #define LIBSSH2_SFTP_REALPATH 2 81 | 82 | /* Flags for sftp_mkdir() */ 83 | #define LIBSSH2_SFTP_DEFAULT_MODE -1 84 | 85 | /* SFTP attribute flag bits */ 86 | #define LIBSSH2_SFTP_ATTR_SIZE 0x00000001 87 | #define LIBSSH2_SFTP_ATTR_UIDGID 0x00000002 88 | #define LIBSSH2_SFTP_ATTR_PERMISSIONS 0x00000004 89 | #define LIBSSH2_SFTP_ATTR_ACMODTIME 0x00000008 90 | #define LIBSSH2_SFTP_ATTR_EXTENDED 0x80000000 91 | 92 | /* SFTP statvfs flag bits */ 93 | #define LIBSSH2_SFTP_ST_RDONLY 0x00000001 94 | #define LIBSSH2_SFTP_ST_NOSUID 0x00000002 95 | 96 | struct _LIBSSH2_SFTP_ATTRIBUTES { 97 | /* If flags & ATTR_* bit is set, then the value in this struct will be 98 | * meaningful Otherwise it should be ignored 99 | */ 100 | unsigned long flags; 101 | 102 | libssh2_uint64_t filesize; 103 | unsigned long uid, gid; 104 | unsigned long permissions; 105 | unsigned long atime, mtime; 106 | }; 107 | 108 | struct _LIBSSH2_SFTP_STATVFS { 109 | libssh2_uint64_t f_bsize; /* file system block size */ 110 | libssh2_uint64_t f_frsize; /* fragment size */ 111 | libssh2_uint64_t f_blocks; /* size of fs in f_frsize units */ 112 | libssh2_uint64_t f_bfree; /* # free blocks */ 113 | libssh2_uint64_t f_bavail; /* # free blocks for non-root */ 114 | libssh2_uint64_t f_files; /* # inodes */ 115 | libssh2_uint64_t f_ffree; /* # free inodes */ 116 | libssh2_uint64_t f_favail; /* # free inodes for non-root */ 117 | libssh2_uint64_t f_fsid; /* file system ID */ 118 | libssh2_uint64_t f_flag; /* mount flags */ 119 | libssh2_uint64_t f_namemax; /* maximum filename length */ 120 | }; 121 | 122 | /* SFTP filetypes */ 123 | #define LIBSSH2_SFTP_TYPE_REGULAR 1 124 | #define LIBSSH2_SFTP_TYPE_DIRECTORY 2 125 | #define LIBSSH2_SFTP_TYPE_SYMLINK 3 126 | #define LIBSSH2_SFTP_TYPE_SPECIAL 4 127 | #define LIBSSH2_SFTP_TYPE_UNKNOWN 5 128 | #define LIBSSH2_SFTP_TYPE_SOCKET 6 129 | #define LIBSSH2_SFTP_TYPE_CHAR_DEVICE 7 130 | #define LIBSSH2_SFTP_TYPE_BLOCK_DEVICE 8 131 | #define LIBSSH2_SFTP_TYPE_FIFO 9 132 | 133 | /* 134 | * Reproduce the POSIX file modes here for systems that are not POSIX 135 | * compliant. 136 | * 137 | * These is used in "permissions" of "struct _LIBSSH2_SFTP_ATTRIBUTES" 138 | */ 139 | /* File type */ 140 | #define LIBSSH2_SFTP_S_IFMT 0170000 /* type of file mask */ 141 | #define LIBSSH2_SFTP_S_IFIFO 0010000 /* named pipe (fifo) */ 142 | #define LIBSSH2_SFTP_S_IFCHR 0020000 /* character special */ 143 | #define LIBSSH2_SFTP_S_IFDIR 0040000 /* directory */ 144 | #define LIBSSH2_SFTP_S_IFBLK 0060000 /* block special */ 145 | #define LIBSSH2_SFTP_S_IFREG 0100000 /* regular */ 146 | #define LIBSSH2_SFTP_S_IFLNK 0120000 /* symbolic link */ 147 | #define LIBSSH2_SFTP_S_IFSOCK 0140000 /* socket */ 148 | 149 | /* File mode */ 150 | /* Read, write, execute/search by owner */ 151 | #define LIBSSH2_SFTP_S_IRWXU 0000700 /* RWX mask for owner */ 152 | #define LIBSSH2_SFTP_S_IRUSR 0000400 /* R for owner */ 153 | #define LIBSSH2_SFTP_S_IWUSR 0000200 /* W for owner */ 154 | #define LIBSSH2_SFTP_S_IXUSR 0000100 /* X for owner */ 155 | /* Read, write, execute/search by group */ 156 | #define LIBSSH2_SFTP_S_IRWXG 0000070 /* RWX mask for group */ 157 | #define LIBSSH2_SFTP_S_IRGRP 0000040 /* R for group */ 158 | #define LIBSSH2_SFTP_S_IWGRP 0000020 /* W for group */ 159 | #define LIBSSH2_SFTP_S_IXGRP 0000010 /* X for group */ 160 | /* Read, write, execute/search by others */ 161 | #define LIBSSH2_SFTP_S_IRWXO 0000007 /* RWX mask for other */ 162 | #define LIBSSH2_SFTP_S_IROTH 0000004 /* R for other */ 163 | #define LIBSSH2_SFTP_S_IWOTH 0000002 /* W for other */ 164 | #define LIBSSH2_SFTP_S_IXOTH 0000001 /* X for other */ 165 | 166 | /* macros to check for specific file types, added in 1.2.5 */ 167 | #define LIBSSH2_SFTP_S_ISLNK(m) \ 168 | (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFLNK) 169 | #define LIBSSH2_SFTP_S_ISREG(m) \ 170 | (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFREG) 171 | #define LIBSSH2_SFTP_S_ISDIR(m) \ 172 | (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFDIR) 173 | #define LIBSSH2_SFTP_S_ISCHR(m) \ 174 | (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFCHR) 175 | #define LIBSSH2_SFTP_S_ISBLK(m) \ 176 | (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFBLK) 177 | #define LIBSSH2_SFTP_S_ISFIFO(m) \ 178 | (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFIFO) 179 | #define LIBSSH2_SFTP_S_ISSOCK(m) \ 180 | (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFSOCK) 181 | 182 | /* SFTP File Transfer Flags -- (e.g. flags parameter to sftp_open()) 183 | * Danger will robinson... APPEND doesn't have any effect on OpenSSH servers */ 184 | #define LIBSSH2_FXF_READ 0x00000001 185 | #define LIBSSH2_FXF_WRITE 0x00000002 186 | #define LIBSSH2_FXF_APPEND 0x00000004 187 | #define LIBSSH2_FXF_CREAT 0x00000008 188 | #define LIBSSH2_FXF_TRUNC 0x00000010 189 | #define LIBSSH2_FXF_EXCL 0x00000020 190 | 191 | /* SFTP Status Codes (returned by libssh2_sftp_last_error() ) */ 192 | #define LIBSSH2_FX_OK 0 193 | #define LIBSSH2_FX_EOF 1 194 | #define LIBSSH2_FX_NO_SUCH_FILE 2 195 | #define LIBSSH2_FX_PERMISSION_DENIED 3 196 | #define LIBSSH2_FX_FAILURE 4 197 | #define LIBSSH2_FX_BAD_MESSAGE 5 198 | #define LIBSSH2_FX_NO_CONNECTION 6 199 | #define LIBSSH2_FX_CONNECTION_LOST 7 200 | #define LIBSSH2_FX_OP_UNSUPPORTED 8 201 | #define LIBSSH2_FX_INVALID_HANDLE 9 202 | #define LIBSSH2_FX_NO_SUCH_PATH 10 203 | #define LIBSSH2_FX_FILE_ALREADY_EXISTS 11 204 | #define LIBSSH2_FX_WRITE_PROTECT 12 205 | #define LIBSSH2_FX_NO_MEDIA 13 206 | #define LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM 14 207 | #define LIBSSH2_FX_QUOTA_EXCEEDED 15 208 | #define LIBSSH2_FX_UNKNOWN_PRINCIPLE 16 /* Initial mis-spelling */ 209 | #define LIBSSH2_FX_UNKNOWN_PRINCIPAL 16 210 | #define LIBSSH2_FX_LOCK_CONFlICT 17 /* Initial mis-spelling */ 211 | #define LIBSSH2_FX_LOCK_CONFLICT 17 212 | #define LIBSSH2_FX_DIR_NOT_EMPTY 18 213 | #define LIBSSH2_FX_NOT_A_DIRECTORY 19 214 | #define LIBSSH2_FX_INVALID_FILENAME 20 215 | #define LIBSSH2_FX_LINK_LOOP 21 216 | 217 | /* Returned by any function that would block during a read/write opperation */ 218 | #define LIBSSH2SFTP_EAGAIN LIBSSH2_ERROR_EAGAIN 219 | 220 | /* SFTP API */ 221 | LIBSSH2_API LIBSSH2_SFTP *libssh2_sftp_init(LIBSSH2_SESSION *session); 222 | LIBSSH2_API int libssh2_sftp_shutdown(LIBSSH2_SFTP *sftp); 223 | LIBSSH2_API unsigned long libssh2_sftp_last_error(LIBSSH2_SFTP *sftp); 224 | LIBSSH2_API LIBSSH2_CHANNEL *libssh2_sftp_get_channel(LIBSSH2_SFTP *sftp); 225 | 226 | /* File / Directory Ops */ 227 | LIBSSH2_API LIBSSH2_SFTP_HANDLE * 228 | libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, 229 | const char *filename, 230 | unsigned int filename_len, 231 | unsigned long flags, 232 | long mode, int open_type); 233 | #define libssh2_sftp_open(sftp, filename, flags, mode) \ 234 | libssh2_sftp_open_ex((sftp), (filename), strlen(filename), (flags), \ 235 | (mode), LIBSSH2_SFTP_OPENFILE) 236 | #define libssh2_sftp_opendir(sftp, path) \ 237 | libssh2_sftp_open_ex((sftp), (path), strlen(path), 0, 0, \ 238 | LIBSSH2_SFTP_OPENDIR) 239 | 240 | LIBSSH2_API ssize_t libssh2_sftp_read(LIBSSH2_SFTP_HANDLE *handle, 241 | char *buffer, size_t buffer_maxlen); 242 | 243 | LIBSSH2_API int libssh2_sftp_readdir_ex(LIBSSH2_SFTP_HANDLE *handle, \ 244 | char *buffer, size_t buffer_maxlen, 245 | char *longentry, 246 | size_t longentry_maxlen, 247 | LIBSSH2_SFTP_ATTRIBUTES *attrs); 248 | #define libssh2_sftp_readdir(handle, buffer, buffer_maxlen, attrs) \ 249 | libssh2_sftp_readdir_ex((handle), (buffer), (buffer_maxlen), NULL, 0, \ 250 | (attrs)) 251 | 252 | LIBSSH2_API ssize_t libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *handle, 253 | const char *buffer, size_t count); 254 | LIBSSH2_API int libssh2_sftp_fsync(LIBSSH2_SFTP_HANDLE *handle); 255 | 256 | LIBSSH2_API int libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle); 257 | #define libssh2_sftp_close(handle) libssh2_sftp_close_handle(handle) 258 | #define libssh2_sftp_closedir(handle) libssh2_sftp_close_handle(handle) 259 | 260 | LIBSSH2_API void libssh2_sftp_seek(LIBSSH2_SFTP_HANDLE *handle, size_t offset); 261 | LIBSSH2_API void libssh2_sftp_seek64(LIBSSH2_SFTP_HANDLE *handle, 262 | libssh2_uint64_t offset); 263 | #define libssh2_sftp_rewind(handle) libssh2_sftp_seek64((handle), 0) 264 | 265 | LIBSSH2_API size_t libssh2_sftp_tell(LIBSSH2_SFTP_HANDLE *handle); 266 | LIBSSH2_API libssh2_uint64_t libssh2_sftp_tell64(LIBSSH2_SFTP_HANDLE *handle); 267 | 268 | LIBSSH2_API int libssh2_sftp_fstat_ex(LIBSSH2_SFTP_HANDLE *handle, 269 | LIBSSH2_SFTP_ATTRIBUTES *attrs, 270 | int setstat); 271 | #define libssh2_sftp_fstat(handle, attrs) \ 272 | libssh2_sftp_fstat_ex((handle), (attrs), 0) 273 | #define libssh2_sftp_fsetstat(handle, attrs) \ 274 | libssh2_sftp_fstat_ex((handle), (attrs), 1) 275 | 276 | /* Miscellaneous Ops */ 277 | LIBSSH2_API int libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp, 278 | const char *source_filename, 279 | unsigned int srouce_filename_len, 280 | const char *dest_filename, 281 | unsigned int dest_filename_len, 282 | long flags); 283 | #define libssh2_sftp_rename(sftp, sourcefile, destfile) \ 284 | libssh2_sftp_rename_ex((sftp), (sourcefile), strlen(sourcefile), \ 285 | (destfile), strlen(destfile), \ 286 | LIBSSH2_SFTP_RENAME_OVERWRITE | \ 287 | LIBSSH2_SFTP_RENAME_ATOMIC | \ 288 | LIBSSH2_SFTP_RENAME_NATIVE) 289 | 290 | LIBSSH2_API int libssh2_sftp_unlink_ex(LIBSSH2_SFTP *sftp, 291 | const char *filename, 292 | unsigned int filename_len); 293 | #define libssh2_sftp_unlink(sftp, filename) \ 294 | libssh2_sftp_unlink_ex((sftp), (filename), strlen(filename)) 295 | 296 | LIBSSH2_API int libssh2_sftp_fstatvfs(LIBSSH2_SFTP_HANDLE *handle, 297 | LIBSSH2_SFTP_STATVFS *st); 298 | 299 | LIBSSH2_API int libssh2_sftp_statvfs(LIBSSH2_SFTP *sftp, 300 | const char *path, 301 | size_t path_len, 302 | LIBSSH2_SFTP_STATVFS *st); 303 | 304 | LIBSSH2_API int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, 305 | const char *path, 306 | unsigned int path_len, long mode); 307 | #define libssh2_sftp_mkdir(sftp, path, mode) \ 308 | libssh2_sftp_mkdir_ex((sftp), (path), strlen(path), (mode)) 309 | 310 | LIBSSH2_API int libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp, 311 | const char *path, 312 | unsigned int path_len); 313 | #define libssh2_sftp_rmdir(sftp, path) \ 314 | libssh2_sftp_rmdir_ex((sftp), (path), strlen(path)) 315 | 316 | LIBSSH2_API int libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp, 317 | const char *path, 318 | unsigned int path_len, 319 | int stat_type, 320 | LIBSSH2_SFTP_ATTRIBUTES *attrs); 321 | #define libssh2_sftp_stat(sftp, path, attrs) \ 322 | libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_STAT, \ 323 | (attrs)) 324 | #define libssh2_sftp_lstat(sftp, path, attrs) \ 325 | libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_LSTAT, \ 326 | (attrs)) 327 | #define libssh2_sftp_setstat(sftp, path, attrs) \ 328 | libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_SETSTAT, \ 329 | (attrs)) 330 | 331 | LIBSSH2_API int libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, 332 | const char *path, 333 | unsigned int path_len, 334 | char *target, 335 | unsigned int target_len, 336 | int link_type); 337 | #define libssh2_sftp_symlink(sftp, orig, linkpath) \ 338 | libssh2_sftp_symlink_ex((sftp), (orig), strlen(orig), (linkpath), \ 339 | strlen(linkpath), LIBSSH2_SFTP_SYMLINK) 340 | #define libssh2_sftp_readlink(sftp, path, target, maxlen) \ 341 | libssh2_sftp_symlink_ex((sftp), (path), strlen(path), (target), (maxlen), \ 342 | LIBSSH2_SFTP_READLINK) 343 | #define libssh2_sftp_realpath(sftp, path, target, maxlen) \ 344 | libssh2_sftp_symlink_ex((sftp), (path), strlen(path), (target), (maxlen), \ 345 | LIBSSH2_SFTP_REALPATH) 346 | 347 | #ifdef __cplusplus 348 | } /* extern "C" */ 349 | #endif 350 | 351 | #endif /* LIBSSH2_SFTP_H */ 352 | -------------------------------------------------------------------------------- /Bin/README.md: -------------------------------------------------------------------------------- 1 | ## libssh.dll 2 | 3 | Ssh-Pacal requires the presence of libssh2.dll in the same directory as the executable. This directory contains Win32 and Win64 binaries created from the latest sources (see the folder CLibs for details). These dynamic libraries are compiled with the WinCng (bcrypt.dll part of the Windows system) cryptographic backend and have no further dependencies. 4 | 5 | 6 | ## Alternative libssh.dll using OpenSSL 7 | 8 | Alternative you can replace them with dynamic libraries that use the OpenSSL backend. If you do so you would need to deploy 9 | 10 | - libssh2.dll 11 | - libcrypto-1_1.dll 12 | - libssl-1_1.dll 13 | 14 | in the same directory as the executable. 15 | 16 | Windows binaries for the above can be found at the [PHP repository](https://windows.php.net/downloads/php-sdk/deps/). 17 | -------------------------------------------------------------------------------- /Bin/Win32/libssh2.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyscripter/Ssh-Pascal/45893661c3226988db1fee302207ac3ea4ef598f/Bin/Win32/libssh2.dll -------------------------------------------------------------------------------- /Bin/Win64/Debug/libssh2.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyscripter/Ssh-Pascal/45893661c3226988db1fee302207ac3ea4ef598f/Bin/Win64/Debug/libssh2.dll -------------------------------------------------------------------------------- /Bin/Win64/libssh2.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyscripter/Ssh-Pascal/45893661c3226988db1fee302207ac3ea4ef598f/Bin/Win64/libssh2.dll -------------------------------------------------------------------------------- /CLibs/BuildWin32Lib.cmd: -------------------------------------------------------------------------------- 1 | Set CurrentDIR=%CD% 2 | echo ------------- Building zlib --------------------- 3 | pushd zlib 4 | git clean -d -f -x 5 | cmake -G "Visual Studio 17 2022" -A Win32 -DCMAKE_POLICY_DEFAULT_CMP0091=NEW -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded -DCMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH=OFF -DCMAKE_INSTALL_PREFIX=./ZlibBin . 6 | cmake --build . --target install --config "Release" 7 | cd ZLibBin\lib 8 | del zlib.lib 9 | ren zlibstatic.lib zlib.lib 10 | popd 11 | echo ----------- Building libssh2 ------------------ 12 | pushd libssh2 13 | git clean -d -f -x 14 | cmake -G "Visual Studio 17 2022" -A Win32 -DCMAKE_POLICY_DEFAULT_CMP0091=NEW -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded -DCMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH=OFF -DBUILD_EXAMPLES=OFF -DBUILD_TESTING=OFF -DENABLE_ZLIB_COMPRESSION=ON -DCRYPTO_BACKEND=WinCNG -DBUILD_SHARED_LIBS=ON -DCMAKE_INSTALL_PREFIX=./WinX32 -DZLIB_LIBRARY=%CurrentDIR%/zlib/ZlibBin/lib/zlib.lib -DZLIB_INCLUDE_DIR=%CurrentDIR%/zlib/ZlibBin/Include". 15 | cmake --build . --target install --config "Release" 16 | popd 17 | copy libssh2\WinX32\Bin\libssh2.dll ..\Bin\Win32 -------------------------------------------------------------------------------- /CLibs/BuildWin64Lib.cmd: -------------------------------------------------------------------------------- 1 | Set CurrentDIR=%CD% 2 | echo ------------- Building zlib --------------------- 3 | pushd zlib 4 | git clean -d -f -x 5 | cmake -G "Visual Studio 17 2022" -A x64 -DCMAKE_POLICY_DEFAULT_CMP0091=NEW -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded -DCMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH=OFF -DCMAKE_INSTALL_PREFIX=./ZlibBin . 6 | cmake --build . --target install --config "Release" 7 | cd ZLibBin\lib 8 | del zlib.lib 9 | ren zlibstatic.lib zlib.lib 10 | popd 11 | echo ----------- Building libssh2 ------------------ 12 | pushd libssh2 13 | git clean -d -f -x 14 | cmake -G "Visual Studio 17 2022" -A x64 -DCMAKE_POLICY_DEFAULT_CMP0091=NEW -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded -DCMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH=OFF -DBUILD_EXAMPLES=OFF -DBUILD_TESTING=OFF -DENABLE_ZLIB_COMPRESSION=ON -DCRYPTO_BACKEND=WinCNG -DBUILD_SHARED_LIBS=ON -DCMAKE_INSTALL_PREFIX=./WinX64 -DZLIB_LIBRARY=%CurrentDIR%/zlib/ZlibBin/lib/zlib.lib -DZLIB_INCLUDE_DIR=%CurrentDIR%/zlib/ZlibBin/Include" . 15 | cmake --build . --target install --config "Release" 16 | popd 17 | copy libssh2\WinX64\Bin\libssh2.dll ..\Bin\Win64 -------------------------------------------------------------------------------- /CLibs/BuildWin64LibDebug.cmd: -------------------------------------------------------------------------------- 1 | Set CurrentDIR=%CD% 2 | echo ------------- Building zlib --------------------- 3 | pushd zlib 4 | git clean -d -f -x 5 | cmake -G "Visual Studio 17 2022" -A x64 -DCMAKE_POLICY_DEFAULT_CMP0091=NEW -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded -DCMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH=OFF -DCMAKE_INSTALL_PREFIX=./ZlibBin . 6 | cmake --build . --target install --config "Release" 7 | cd ZLibBin\lib 8 | del zlib.lib 9 | ren zlibstatic.lib zlib.lib 10 | popd 11 | echo ----------- Building libssh2 ------------------ 12 | pushd libssh2 13 | git clean -d -f -x 14 | cmake -G "Visual Studio 17 2022" -A x64 -DCMAKE_BUILD_TYPE=Debug -DCMAKE_POLICY_DEFAULT_CMP0091=NEW -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded -DCMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH=OFF -DBUILD_EXAMPLES=OFF -DBUILD_TESTING=OFF -DENABLE_ZLIB_COMPRESSION=ON -DCRYPTO_BACKEND=WinCNG -DBUILD_SHARED_LIBS=ON -DCMAKE_INSTALL_PREFIX=./WinX64 -DZLIB_LIBRARY=%CurrentDIR%/zlib/ZlibBin/lib/zlib.lib -DZLIB_INCLUDE_DIR=%CurrentDIR%/zlib/ZlibBin/Include" . 15 | cmake --build . --target install --config "Debug" 16 | popd 17 | copy libssh2\WinX64\Bin\libssh2.dll ..\Bin\Win64\Debug -------------------------------------------------------------------------------- /CLibs/CloneLibs.cmd: -------------------------------------------------------------------------------- 1 | git clone https://github.com/libssh2/libssh2.git 2 | git clone https://github.com/madler/zlib.git 3 | -------------------------------------------------------------------------------- /CLibs/README.md: -------------------------------------------------------------------------------- 1 | ## Instructions for generating the dynamic libraries from the latest sources 2 | 3 | ### Requirements 4 | - [Git for Windows](https://git-scm.com/download/win) installed 5 | - [Visual Studio](https://visualstudio.microsoft.com/) installed. [Community edition](https://visualstudio.microsoft.com/vs/community/) will do. 6 | - Visual Studio includes [CMake](https://cmake.org/) but you need to make sure is accessible from the system path before executing the following steps. 7 | 8 | ### Steps 9 | - Run CloneLibs.cmd to clone zlib and libssh2 10 | - Run BuildWin64Lib to build libssh2.dll 64 bits. It will build the dll with the WinCng (bcrypt.dll part of the Windows system) backend and copy it to the Bin\Win64 directory 11 | - Run BuildWin32Lib to build libssh2.dll 32 bits. It will build the dll with the WinCng (bcrypt.dll part of the Windows system) backend and copy it to the Bin\Win32 directory 12 | -------------------------------------------------------------------------------- /Demos/LocalForward/LocalForward.dpr: -------------------------------------------------------------------------------- 1 | program LocalForward; 2 | { 3 | Run and while the project is running open a browser at http://localhost:12345/ 4 | You should see http://detectportal.firefox.com/success.txt 5 | } 6 | 7 | {$APPTYPE CONSOLE} 8 | 9 | uses 10 | Winapi.Winsock2, 11 | System.SysUtils, 12 | System.NetEncoding, 13 | System.Classes, 14 | libssh2 in '..\..\Source\libssh2.pas', 15 | SocketUtils in '..\..\Source\SocketUtils.pas', 16 | Ssh2Client in '..\..\Source\Ssh2Client.pas', 17 | SshTunnel in '..\..\Source\SshTunnel.pas'; 18 | 19 | function KeybIntCallback(const AuthName, AuthInstruction, Prompt: string; 20 | Echo: Boolean): string; 21 | begin 22 | if AuthName <> '' then WriteLn('Authorization Name: ', AuthName); 23 | if AuthInstruction <> '' then WriteLn('Authorization Instruction: ', AuthInstruction); 24 | Write(Prompt); 25 | // if Echo is False then you should mask the input 26 | // See https://stackoverflow.com/questions/3671042/mask-password-input-in-a-console-app 27 | ReadLn(Result); 28 | end; 29 | 30 | procedure Main; 31 | const 32 | SshPort = 22; 33 | RemoteHost = 'detectportal.firefox.com'; 34 | LocalPort = 12345; 35 | RemotePort = 80; 36 | var 37 | Host: string; 38 | UserName: string; 39 | Session: ISshSession; 40 | SshTunnel: ISshTunnel; 41 | Thread: TThread; 42 | begin 43 | if ParamCount <> 2 then begin 44 | WriteLn('Usage: LocalForward Host, UserName'); 45 | Exit; 46 | end; 47 | 48 | Host := ParamStr(1); 49 | UserName := ParamStr(2); 50 | 51 | Session := CreateSession(Host, SshPort); 52 | //Session.UseCompression := True; 53 | Session.SetKeybInteractiveCallback(KeybIntCallback); 54 | 55 | Session.Connect; 56 | WriteLn(Session.HostBanner); 57 | WriteLn(Session.SessionMethods); 58 | 59 | if not Session.UserAuth(UserName) then 60 | begin 61 | WriteLn('Authorization Failure'); 62 | Exit; 63 | end; 64 | 65 | SshTunnel := CreateSshTunnel(Session); 66 | Thread := TThread.CreateAnonymousThread( 67 | procedure 68 | begin 69 | SshTunnel.ForwardLocalPort(LocalPort, RemoteHost, RemotePort); 70 | end); 71 | Thread.FreeOnTerminate := False; 72 | Thread.Start; 73 | WriteLn; 74 | WriteLn('Tunnel from localhost:', LocalPort, ' to ', RemoteHost, ':', 75 | RemotePort, ' established'); 76 | WriteLn; 77 | WriteLn('Press Enter to terminate'); 78 | ReadLn; 79 | SshTunnel.Cancel; 80 | if not Thread.Finished then 81 | begin 82 | Thread.WaitFor; 83 | Thread.Free; 84 | end; 85 | WriteLn('All done!'); 86 | end; 87 | 88 | begin 89 | ReportMemoryLeaksOnShutdown := True; 90 | try 91 | Main; 92 | except 93 | on E: Exception do 94 | WriteLn(E.ClassName, ': ', E.Message); 95 | end; 96 | ReadLn; 97 | end. 98 | -------------------------------------------------------------------------------- /Demos/README.md: -------------------------------------------------------------------------------- 1 | ### Instructions for running the demos 2 | 3 | - Open the dpr file in Delphi 4 | - In Project, Options under "Compiler Options" specify specify "..\\..\\Bin\\$(Platform)" as the output directory. This will avoid the need to copy the deployment libraries to the executable directory. 5 | - Use Run, Parameters to provide suitable command-line parameters 6 | - Run or debug the demos from the Delphi IDE. -------------------------------------------------------------------------------- /Demos/SFtpSend/SftpSend.dpr: -------------------------------------------------------------------------------- 1 | program SftpSend; 2 | { 3 | Includes testing of different Sftp features 4 | } 5 | 6 | {$APPTYPE CONSOLE} 7 | 8 | uses 9 | Winapi.Winsock2, 10 | System.SysUtils, 11 | System.NetEncoding, 12 | System.Classes, 13 | libssh2 in '..\..\Source\libssh2.pas', 14 | SocketUtils in '..\..\Source\SocketUtils.pas', 15 | Ssh2Client in '..\..\Source\Ssh2Client.pas', 16 | libssh2_sftp in '..\..\Source\libssh2_sftp.pas', 17 | SftpClient in '..\..\Source\SftpClient.pas'; 18 | 19 | function KeybIntCallback(const AuthName, AuthInstruction, Prompt: string; 20 | Echo: Boolean): string; 21 | begin 22 | if AuthName <> '' then WriteLn('Authorization Name: ', AuthName); 23 | if AuthInstruction <> '' then WriteLn('Authorization Instruction: ', AuthInstruction); 24 | Write(Prompt); 25 | // if Echo is False then you should mask the input 26 | // See https://stackoverflow.com/questions/3671042/mask-password-input-in-a-console-app 27 | ReadLn(Result); 28 | end; 29 | 30 | procedure Main; 31 | Var 32 | Host: string; 33 | UserName: string; 34 | Session: ISshSession; 35 | Sftp: ISftpClient; 36 | RemotePath: string; 37 | LocalPath: string; 38 | FilePath: string; 39 | begin 40 | 41 | if ParamCount <> 4 then begin 42 | WriteLn('Usage: SftpSend Host, UserName, RemoteFile, LocalFile'); 43 | Exit; 44 | end; 45 | 46 | Host := ParamStr(1); 47 | UserName := ParamStr(2); 48 | LocalPath := ParamStr(3); 49 | RemotePath := ParamStr(4); 50 | 51 | Session := CreateSession(Host, 22); 52 | //Session.UseCompression := True; 53 | Session.SetKeybInteractiveCallback(KeybIntCallback); 54 | 55 | Session.Connect; 56 | WriteLn(Session.HostBanner); 57 | WriteLn(Session.SessionMethods); 58 | 59 | //if not Session.UserAuthInteractive(UserName) then 60 | if not Session.UserAuth(UserName) then 61 | begin 62 | WriteLn('Authorization Failure'); 63 | Exit; 64 | end; 65 | 66 | Sftp := CreateSftpClient(Session); 67 | WriteLn('Current directory: ', Sftp.GetCurrentDir); 68 | 69 | FilePath := Sftp.ExtractFilePath(RemotePath); 70 | Assert(Sftp.DirectoryExists(FilePath)); 71 | 72 | FilePath := FilePath + 'tempdir'; 73 | Assert(Sftp.CreateDir(FilePath)); 74 | Assert(not Sftp.FileExists(FilePath)); 75 | Assert(Sftp.DirectoryExists(FilePath)); 76 | Assert(Sftp.RemoveDir(FilePath)); 77 | Assert(not Sftp.DirectoryExists(FilePath)); 78 | 79 | // tilde expansion 80 | Assert(Sftp.ForceDirectories('~/tmpdir/tmpdir')); 81 | Assert(Sftp.RemoveDir('~/tmpdir/tmpdir')); 82 | Assert(Sftp.RemoveDir('~/tmpdir')); 83 | 84 | // ForceDirectories 85 | FilePath := Sftp.ExtractFilePath(RemotePath); 86 | FilePath := FilePath + 'tempdir' + string(Sftp.PathDelimiter) + 'tempdir'; 87 | Assert(Sftp.ForceDirectories(FilePath)); 88 | Assert(Sftp.DirectoryExists(FilePath)); 89 | Assert(Sftp.RemoveDir(FilePath)); 90 | Assert(Sftp.RemoveDir(Sftp.ExtractFilePath(FilePath))); 91 | 92 | //Symbolic links - tilde expansion 93 | Assert(Sftp.CreateSymLink('~/link', RemotePath)); 94 | Assert(Sftp.SftpType('~/link', False) = sitSymbolicLink); 95 | Assert(Sftp.DeleteFile('~/link')); 96 | 97 | Sftp.Send(LocalPath, RemotePath); 98 | Assert(Sftp.RealPath(RemotePath) = RemotePath); 99 | Assert(Sftp.FileExists(RemotePath)); 100 | Assert(not Sftp.DirectoryExists(RemotePath)); 101 | Assert(Sftp.DeleteFile(RemotePath)); 102 | Assert(not Sftp.FileExists(RemotePath)); 103 | 104 | Writeln('All done!'); 105 | end; 106 | 107 | begin 108 | ReportMemoryLeaksOnShutdown := True; 109 | try 110 | Main; 111 | except 112 | on E: Exception do 113 | Writeln(E.ClassName, ': ', E.Message); 114 | end; 115 | ReadLn; 116 | end. 117 | -------------------------------------------------------------------------------- /Demos/ScpRecv/ScpRecv.dpr: -------------------------------------------------------------------------------- 1 | program ScpRecv; 2 | 3 | {$APPTYPE CONSOLE} 4 | 5 | uses 6 | Winapi.Winsock2, 7 | System.SysUtils, 8 | System.NetEncoding, 9 | System.Classes, 10 | libssh2 in '..\..\Source\libssh2.pas', 11 | SocketUtils in '..\..\Source\SocketUtils.pas', 12 | Ssh2Client in '..\..\Source\Ssh2Client.pas', 13 | libssh2_sftp in '..\..\Source\libssh2_sftp.pas'; 14 | 15 | function KeybIntCallback(const AuthName, AuthInstruction, Prompt: string; 16 | Echo: Boolean): string; 17 | begin 18 | if AuthName <> '' then WriteLn('Authorization Name: ', AuthName); 19 | if AuthInstruction <> '' then WriteLn('Authorization Instruction: ', AuthInstruction); 20 | Write(Prompt); 21 | // if Echo is False then you should mask the input 22 | // See https://stackoverflow.com/questions/3671042/mask-password-input-in-a-console-app 23 | ReadLn(Result); 24 | end; 25 | 26 | procedure Main; 27 | Var 28 | Host: string; 29 | UserName: string; 30 | RemotePath: string; 31 | LocalPath: string; 32 | Session: ISshSession; 33 | Scp: IScp; 34 | begin 35 | 36 | if ParamCount <> 4 then begin 37 | WriteLn('Usage: SpcRecv Host, UserName, RemoteFile, LocalFile'); 38 | Exit; 39 | end; 40 | 41 | Host := ParamStr(1); 42 | UserName := ParamStr(2); 43 | RemotePath := ParamStr(3); 44 | LocalPath := ParamStr(4); 45 | 46 | Session := CreateSession(Host, 22); 47 | //Session.UseCompression := True; 48 | Session.SetKeybInteractiveCallback(KeybIntCallback); 49 | 50 | Session.Connect; 51 | WriteLn(Session.HostBanner); 52 | WriteLn(Session.SessionMethods); 53 | 54 | if not Session.UserAuth(UserName) then 55 | begin 56 | WriteLn('Authorization Failure'); 57 | Exit; 58 | end; 59 | 60 | Scp := CreateScp(Session); 61 | Scp.Receive(RemotePath, LocalPath); 62 | 63 | Writeln('All done!'); 64 | end; 65 | 66 | begin 67 | ReportMemoryLeaksOnShutdown := True; 68 | try 69 | Main; 70 | except 71 | on E: Exception do 72 | Writeln(E.ClassName, ': ', E.Message); 73 | end; 74 | ReadLn; 75 | end. 76 | -------------------------------------------------------------------------------- /Demos/ScpSend/ScpSend.dpr: -------------------------------------------------------------------------------- 1 | program ScpSend; 2 | 3 | {$APPTYPE CONSOLE} 4 | 5 | uses 6 | Winapi.Winsock2, 7 | System.SysUtils, 8 | System.NetEncoding, 9 | System.Classes, 10 | libssh2 in '..\..\Source\libssh2.pas', 11 | SocketUtils in '..\..\Source\SocketUtils.pas', 12 | Ssh2Client in '..\..\Source\Ssh2Client.pas', 13 | libssh2_sftp in '..\..\Source\libssh2_sftp.pas'; 14 | 15 | function KeybIntCallback(const AuthName, AuthInstruction, Prompt: string; 16 | Echo: Boolean): string; 17 | begin 18 | if AuthName <> '' then WriteLn('Authorization Name: ', AuthName); 19 | if AuthInstruction <> '' then WriteLn('Authorization Instruction: ', AuthInstruction); 20 | Write(Prompt); 21 | // if Echo is False then you should mask the input 22 | // See how at https://stackoverflow.com/questions/3671042/mask-password-input-in-a-console-app 23 | ReadLn(Result); 24 | end; 25 | 26 | procedure Main; 27 | Var 28 | Host: string; 29 | UserName: string; 30 | RemotePath: string; 31 | LocalPath: string; 32 | Session: ISshSession; 33 | Scp: IScp; 34 | begin 35 | 36 | if ParamCount <> 4 then begin 37 | WriteLn('Usage: SpcSend Host, UserName, LocalFile, RemoteFile'); 38 | Exit; 39 | end; 40 | 41 | Host := ParamStr(1); 42 | UserName := ParamStr(2); 43 | LocalPath := ParamStr(3); 44 | RemotePath := ParamStr(4); 45 | 46 | Session := CreateSession(Host, 22); 47 | Session.SetKeybInteractiveCallback(KeybIntCallback); 48 | Session.Connect; 49 | WriteLn(Session.HostBanner); 50 | 51 | if not Session.UserAuth(UserName) then 52 | begin 53 | WriteLn('Authorization Failure'); 54 | Exit; 55 | end; 56 | 57 | Scp := CreateScp(Session); 58 | Scp.Send(LocalPath, RemotePath); 59 | 60 | Writeln('All done!'); 61 | end; 62 | 63 | begin 64 | ReportMemoryLeaksOnShutdown := True; 65 | try 66 | Main; 67 | except 68 | on E: Exception do 69 | Writeln(E.ClassName, ': ', E.Message); 70 | end; 71 | ReadLn; 72 | end. 73 | -------------------------------------------------------------------------------- /Demos/SftpDir/SftpDir.dpr: -------------------------------------------------------------------------------- 1 | program SftpDir; 2 | 3 | {$APPTYPE CONSOLE} 4 | 5 | uses 6 | Winapi.Winsock2, 7 | System.SysUtils, 8 | System.NetEncoding, 9 | System.Classes, 10 | libssh2 in '..\..\Source\libssh2.pas', 11 | SocketUtils in '..\..\Source\SocketUtils.pas', 12 | Ssh2Client in '..\..\Source\Ssh2Client.pas', 13 | libssh2_sftp in '..\..\Source\libssh2_sftp.pas', 14 | SftpClient in '..\..\Source\SftpClient.pas'; 15 | 16 | function KeybIntCallback(const AuthName, AuthInstruction, Prompt: string; 17 | Echo: Boolean): string; 18 | begin 19 | if AuthName <> '' then WriteLn('Authorization Name: ', AuthName); 20 | if AuthInstruction <> '' then WriteLn('Authorization Instruction: ', AuthInstruction); 21 | Write(Prompt); 22 | // if Echo is False then you should mask the input 23 | // See https://stackoverflow.com/questions/3671042/mask-password-input-in-a-console-app 24 | ReadLn(Result); 25 | end; 26 | 27 | procedure Main; 28 | Var 29 | Host: string; 30 | UserName: string; 31 | Session: ISshSession; 32 | Sftp: ISftpClient; 33 | RemotePath: string; 34 | Directory: string; 35 | Item: TSftpItem; 36 | begin 37 | 38 | if ParamCount <> 3 then begin 39 | WriteLn('Usage: SftpDir Host, UserName, Directory'); 40 | Exit; 41 | end; 42 | 43 | Host := ParamStr(1); 44 | UserName := ParamStr(2); 45 | Directory := ParamStr(3); 46 | 47 | Session := CreateSession(Host, 22); 48 | //Session.UseCompression := True; 49 | Session.SetKeybInteractiveCallback(KeybIntCallback); 50 | 51 | Session.Connect; 52 | WriteLn(Session.HostBanner); 53 | WriteLn(Session.SessionMethods); 54 | 55 | if not Session.UserAuth(UserName) then 56 | begin 57 | WriteLn('Authorization Failure'); 58 | Exit; 59 | end; 60 | 61 | Sftp := CreateSftpClient(Session); 62 | 63 | WriteLn; 64 | WriteLn('Directory listing of ', Directory); 65 | for Item in Sftp.DirContent(Directory) do 66 | WriteLn(Item.LongEntry); 67 | 68 | Writeln('All done!'); 69 | end; 70 | 71 | begin 72 | ReportMemoryLeaksOnShutdown := True; 73 | try 74 | Main; 75 | except 76 | on E: Exception do 77 | Writeln(E.ClassName, ': ', E.Message); 78 | end; 79 | ReadLn; 80 | end. 81 | -------------------------------------------------------------------------------- /Demos/SftpRecv/SftpRecv.dpr: -------------------------------------------------------------------------------- 1 | program SftpRecv; 2 | 3 | {$APPTYPE CONSOLE} 4 | 5 | uses 6 | Winapi.Winsock2, 7 | System.SysUtils, 8 | System.NetEncoding, 9 | System.Classes, 10 | libssh2 in '..\..\Source\libssh2.pas', 11 | SocketUtils in '..\..\Source\SocketUtils.pas', 12 | Ssh2Client in '..\..\Source\Ssh2Client.pas', 13 | libssh2_sftp in '..\..\Source\libssh2_sftp.pas', 14 | SftpClient in '..\..\Source\SftpClient.pas'; 15 | 16 | function KeybIntCallback(const AuthName, AuthInstruction, Prompt: string; 17 | Echo: Boolean): string; 18 | begin 19 | if AuthName <> '' then WriteLn('Authorization Name: ', AuthName); 20 | if AuthInstruction <> '' then WriteLn('Authorization Instruction: ', AuthInstruction); 21 | Write(Prompt); 22 | // if Echo is False then you should mask the input 23 | // See https://stackoverflow.com/questions/3671042/mask-password-input-in-a-console-app 24 | ReadLn(Result); 25 | end; 26 | 27 | procedure Main; 28 | Var 29 | Host: string; 30 | UserName: string; 31 | Session: ISshSession; 32 | Sftp: ISftpClient; 33 | RemotePath: string; 34 | LocalPath: string; 35 | begin 36 | 37 | if ParamCount <> 4 then begin 38 | WriteLn('Usage: SftpRev Host, UserName, RemoteFile, LocalFile'); 39 | Exit; 40 | end; 41 | 42 | Host := ParamStr(1); 43 | UserName := ParamStr(2); 44 | RemotePath := ParamStr(3); 45 | LocalPath := ParamStr(4); 46 | 47 | Session := CreateSession(Host, 22); 48 | Session.UseCompression := True; 49 | Session.SetKeybInteractiveCallback(KeybIntCallback); 50 | 51 | Session.Connect; 52 | WriteLn(Session.HostBanner); 53 | WriteLn(Session.SessionMethods); 54 | 55 | //if not Session.UserAuthInteractive(UserName) then 56 | if not Session.UserAuth(UserName) then 57 | begin 58 | WriteLn('Authorization Failure'); 59 | Exit; 60 | end; 61 | 62 | Sftp := CreateSftpClient(Session); 63 | Sftp.Receive(RemotePath, LocalPath); 64 | 65 | Writeln('All done!'); 66 | end; 67 | 68 | begin 69 | ReportMemoryLeaksOnShutdown := True; 70 | try 71 | Main; 72 | except 73 | on E: Exception do 74 | Writeln(E.ClassName, ': ', E.Message); 75 | end; 76 | ReadLn; 77 | end. 78 | -------------------------------------------------------------------------------- /Demos/SshExec/SshExec.dpr: -------------------------------------------------------------------------------- 1 | program SshExec; 2 | 3 | {$APPTYPE CONSOLE} 4 | 5 | uses 6 | Winapi.Winsock2, 7 | System.SysUtils, 8 | System.Classes, 9 | libssh2 in '..\..\Source\libssh2.pas', 10 | SocketUtils in '..\..\Source\SocketUtils.pas', 11 | Ssh2Client in '..\..\Source\Ssh2Client.pas', 12 | libssh2_sftp in '..\..\Source\libssh2_sftp.pas', 13 | SFtpClient in '..\..\Source\SFtpClient.pas'; 14 | 15 | function KeybIntCallback(const AuthName, AuthInstruction, Prompt: string; 16 | Echo: Boolean): string; 17 | begin 18 | if AuthName <> '' then WriteLn('Authorization Name: ', AuthName); 19 | if AuthInstruction <> '' then WriteLn('Authorization Instruction: ', AuthInstruction); 20 | Write(Prompt); 21 | // if Echo is False then you should mask the input 22 | // See https://stackoverflow.com/questions/3671042/mask-password-input-in-a-console-app 23 | ReadLn(Result); 24 | end; 25 | 26 | procedure Main; 27 | Var 28 | Host: string; 29 | UserName: string; 30 | Command: string; 31 | Session: ISshSession; 32 | SshExec: ISshExec; 33 | Output: string; 34 | ErrOutput: string; 35 | ExitCode: Integer; 36 | begin 37 | 38 | if ParamCount <> 3 then begin 39 | WriteLn('Usage: SshExec Host, UserName, Command'); 40 | Exit; 41 | end; 42 | 43 | Host := ParamStr(1); 44 | UserName := ParamStr(2); 45 | Command := ParamStr(3); 46 | 47 | Session := CreateSession(Host, 22); 48 | //Session.UseCompression := True; 49 | Session.SetKeybInteractiveCallback(KeybIntCallback); 50 | 51 | Session.Connect; 52 | WriteLn(Session.HostBanner); 53 | WriteLn(Session.SessionMethods); 54 | 55 | //if not Session.UserAuthInteractive(UserName) then 56 | if not Session.UserAuth(UserName) then 57 | begin 58 | WriteLn('Authorization Failure'); 59 | Exit; 60 | end; 61 | 62 | SshExec := CreateSshExec(Session); 63 | SshExec.Exec(Command, Output, ErrOutput, ExitCode); 64 | WriteLn('Command:', Command); 65 | if Output <> '' then begin 66 | WriteLn('Output:'); 67 | WriteLn(Output); 68 | end; 69 | if ErrOutput <> '' then begin 70 | WriteLn('Error Output:'); 71 | WriteLn(ErrOutput); 72 | end; 73 | WriteLn('Exit Code:', ExitCode.ToString); 74 | WriteLn('All done!'); 75 | end; 76 | 77 | begin 78 | ReportMemoryLeaksOnShutdown := True; 79 | try 80 | Main; 81 | except 82 | on E: Exception do 83 | WriteLn(E.ClassName, ': ', E.Message); 84 | end; 85 | ReadLn; 86 | end. 87 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 pyscripter 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ssh-Pascal 2 | Pascal Ssh library based on [libssh2](https://www.libssh2.org/). Libssh2 is a mature ssh library used by PHP (built-in), Rust and many other languages and applications. 3 | 4 | ## Features 5 | - Extensive ssh features 6 | - Support for different authorization methods (publickey, password, agent, hostbased and keyboard-interactive) 7 | - Known host management. 8 | - Execution of commands on the host capturing stdout and stderr 9 | - Comprehensive sftp support 10 | - Port forwarding (currently only local) 11 | - scp support 12 | - High-level pascal-friendly, interface-based wrapping of ssh functionality. 13 | - Lower-level usage is possible. 14 | 15 | ## Installation 16 | There are no components to install. Just clone the repository and add the Source folder to your library path. 17 | 18 | ## Deployment 19 | The libssh2.dll dynamic library should be deployed in the same directory as the executable. The Bin directory contains Win32 and Win64 binaries. 20 | 21 | ## Documentation 22 | Currently the best (only) way to learn how to use the library is to study the demos and the source code. 23 | 24 | ## Platform and FPC support 25 | Currently only Delphi (versions with generics) and Windows 32-bit and 64-bit are supported 26 | libssh2 is available on Linux, iOS, OSX, and other platforms. So the library could be extended to provide support for such platforms. Pull requests to provide compatibility with other platforms and/or FPC would be welcome. 27 | 28 | ## Limitations 29 | - scp does not work with Windows hosts (Sftp does though). 30 | - keyboard-interactive authorization does not work with Windows hosts (it reverts to password authorization). 31 | 32 | ## Credits 33 | The C header translations draw from https://bitbucket.org/ZeljkoMarjanovic/libssh2-delphi 34 | Copyright (c) 2010, Zeljko Marjanovic (MPL 1.1). Everything else was written from scratch. 35 | -------------------------------------------------------------------------------- /Source/SftpClient.pas: -------------------------------------------------------------------------------- 1 | unit SftpClient; 2 | { 3 | 4 | Copyright (c) 2020 Kiriakos Vlahos (PyScripter) 5 | Delphi wrapper of libssh2 (https://www.libssh2.org/) 6 | 7 | The C header translation and the SFTP implementation draw from 8 | https://bitbucket.org/ZeljkoMarjanovic/libssh2-delphi 9 | Copyright (c) 2010, Zeljko Marjanovic (MPL 1.1) 10 | 11 | Released under the MIT Licence 12 | } 13 | 14 | interface 15 | 16 | Uses 17 | WinApi.Windows, 18 | System.SysUtils, 19 | System.Classes, 20 | System.Generics.Collections, 21 | libssh2, 22 | libssh2_sftp, 23 | Ssh2Client; 24 | 25 | type 26 | ESftpErr = class(Exception); 27 | TSFTPItemType = (sitUnknown, sitDirectory, sitFile, sitSymbolicLink, 28 | sitBlockDev, sitCharDev, sitFIFO, sitSocket); 29 | 30 | TSFTPStatData = record 31 | end; 32 | 33 | TSftpItem = record 34 | FileName: string; 35 | LongEntry: string; 36 | ItemType: TSFTPItemType; 37 | FileSize: UInt64; 38 | UID: UInt; 39 | GID: UInt; 40 | Permissions: TFilePermissions; 41 | LastAccessTime: TDateTime; // UTC 42 | LastModificationTime: TDateTime; // UTC 43 | Hidden: Boolean; 44 | end; 45 | 46 | TSftpItems = TArray; 47 | 48 | ISftpClient = interface 49 | ['{3F365360-444A-42B8-9FD3-AD9AAE497F60}'] 50 | procedure SetBufferSize(Size: Int64); 51 | procedure SetTransferProgressCallback(Callback: TTransferProgressCallback); 52 | procedure Cancel; 53 | property BufferSize: Int64 write SetBufferSize; 54 | procedure RaiseLastSFTPError(Const Op: string); 55 | function SftpType(Name: string; FollowLink: Boolean = True): TSFTPItemType; 56 | function GetPathDelimiter: AnsiChar; 57 | function GetWindowsHost: Boolean; 58 | // Directories 59 | function GetCurrentDir: string; 60 | function CreateDir(const Dir: string; Permissions: TFilePermissions = FPDefault): Boolean; 61 | function ForceDirectories(Dir: string): Boolean; 62 | function RemoveDir(const Dir: string): Boolean; 63 | function DirectoryExists(const Directory: string; FollowLink: Boolean = True): Boolean; 64 | function ExcludeTrailingPathDelimiter(const S: string): string; 65 | function IncludeTrailingPathDelimiter(const S: string): string; 66 | function ExtractFileName(const FileName: string): string; 67 | function DirContent(const Dir: string): TSftpItems; 68 | // Files 69 | function FileExists(const FileName: string; FollowLink: Boolean = True): Boolean; 70 | function DeleteFile(const FileName: string): Boolean; 71 | function Rename(const OldName, NewName: string): Boolean; // also works with directories 72 | function ExtractFilePath(const FileName: string): string; 73 | // Symbolic Links 74 | function RealPath(Name: string): string; 75 | function CreateSymLink(const Link, Target: string): Boolean; 76 | //Send and Receive 77 | procedure Receive(const RemoteFile: string; Stream: TStream); overload; 78 | procedure Receive(const RemoteFile, LocalFile: string; Overwrite:Boolean = True); overload; 79 | procedure Send(Stream: TStream; const RemoteFile: string; 80 | Overwrite: Boolean = True; Permissions: TFilePermissions = FPDefault); overload; 81 | procedure Send(const LocalFile, RemoteFile: string; 82 | Overwrite: Boolean = True; Permissions: TFilePermissions = FPDefault); overload; 83 | // Copy Files and Directories 84 | // Source can be a file or a directory and may include a file mask 85 | // Dest is either a file or a directory 86 | procedure CopyToHost(const Source, Dest: string; Recursive: Boolean = True; 87 | Overwrite: Boolean = True; Permissions: TFilePermissions = FPDefault); overload; 88 | procedure CopyFromHost(const Source, Dest: string; Recursive: Boolean = True; 89 | Overwrite: Boolean = True); overload; 90 | property WindowsHost: Boolean read GetWindowsHost; 91 | 92 | property PathDelimiter: AnsiChar read GetPathDelimiter; 93 | property CurrentDir: string read GetCurrentDir; 94 | end; 95 | 96 | // Factory method 97 | function CreateSftpClient(Session: ISshSession): ISftpClient; 98 | 99 | implementation 100 | Uses 101 | System.SysConst, 102 | System.Types, 103 | System.DateUtils, 104 | System.IOUtils, 105 | System.Masks, 106 | System.Generics.Defaults; 107 | 108 | {$region Support stuff} 109 | resourcestring 110 | Err_SftpInit = 'Could not initialize Sftp'; 111 | Err_Sftp = 'Sftp error: %s (%d), on API "%s"'; 112 | Err_FX_EOF = 'End of file'; 113 | Err_FX_NO_SUCH_FILE = 'No such file'; 114 | Err_FX_PERMISSION_DENIED = 'Permission denied'; 115 | Err_FX_FAILURE = 'Failure'; 116 | Err_FX_BAD_MESSAGE = 'Bad messagge'; 117 | Err_FX_NO_CONNECTION = 'No connection'; 118 | Err_FX_CONNECTION_LOST = 'Connection lost'; 119 | Err_FX_OP_UNSUPPORTED = 'Operation unsupported'; 120 | Err_FX_INVALID_HANDLE = 'Invalid handle'; 121 | Err_FX_NO_SUCH_PATH = 'No such path'; 122 | Err_FX_FILE_ALREADY_EXISTS = 'File exists'; 123 | Err_FX_WRITE_PROTECT = 'Write protect'; 124 | Err_FX_NO_MEDIA = 'No media'; 125 | Err_FX_NO_SPACE_ON_FILESYSTEM = 'No space on filesystem'; 126 | Err_FX_QUOTA_EXCEEDED = 'Quota exceeded'; 127 | Err_LIBSSH2_FX_UNKNOWN_PRINCIPAL = 'Unknown principal'; 128 | Err_LIBSSH2_FX_LOCK_CONFLICT = 'Lock conflict'; 129 | Err_LIBSSH2_FX_DIR_NOT_EMPTY = 'Directory not empty'; 130 | Err_LIBSSH2_FX_NOT_A_DIRECTORY = 'Not a directory'; 131 | Err_LIBSSH2_FX_INVALID_FILENAME = 'Invalid filename'; 132 | Err_LIBSSH2_FX_LINK_LOOP = 'Link loop'; 133 | Err_LIBSSH2_UNKNOWN = 'Unknown error'; 134 | Err_NotAFile = '"%s" is not a file'; 135 | Err_SessionNotAuth = 'The session is not connected and authorised'; 136 | Err_InvalideSource = 'The source of a copy operation is not valid'; 137 | Err_InvalideDest = 'The destination of a copy operation is not valid'; 138 | 139 | function SftpErrorMsg(ErrNo: ULong): string; 140 | begin 141 | case ErrNo of 142 | LIBSSH2_FX_EOF: 143 | Result := Err_FX_EOF; 144 | LIBSSH2_FX_NO_SUCH_FILE: 145 | Result := Err_FX_NO_SUCH_FILE; 146 | LIBSSH2_FX_PERMISSION_DENIED: 147 | Result := Err_FX_PERMISSION_DENIED; 148 | LIBSSH2_FX_FAILURE: 149 | Result := Err_FX_FAILURE; 150 | LIBSSH2_FX_BAD_MESSAGE: 151 | Result := Err_FX_BAD_MESSAGE; 152 | LIBSSH2_FX_NO_CONNECTION: 153 | Result := Err_FX_NO_CONNECTION; 154 | LIBSSH2_FX_CONNECTION_LOST: 155 | Result := Err_FX_CONNECTION_LOST; 156 | LIBSSH2_FX_OP_UNSUPPORTED: 157 | Result := Err_FX_OP_UNSUPPORTED; 158 | LIBSSH2_FX_INVALID_HANDLE: 159 | Result := Err_FX_INVALID_HANDLE; 160 | LIBSSH2_FX_NO_SUCH_PATH: 161 | Result := Err_FX_NO_SUCH_PATH; 162 | LIBSSH2_FX_FILE_ALREADY_EXISTS: 163 | Result := Err_FX_FILE_ALREADY_EXISTS; 164 | LIBSSH2_FX_WRITE_PROTECT: 165 | Result := Err_FX_WRITE_PROTECT; 166 | LIBSSH2_FX_NO_MEDIA: 167 | Result := Err_FX_NO_MEDIA; 168 | LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM: 169 | Result := Err_FX_NO_SPACE_ON_FILESYSTEM; 170 | LIBSSH2_FX_QUOTA_EXCEEDED: 171 | Result := Err_FX_QUOTA_EXCEEDED; 172 | LIBSSH2_FX_UNKNOWN_PRINCIPAL: 173 | Result := Err_LIBSSH2_FX_UNKNOWN_PRINCIPAL; 174 | LIBSSH2_FX_LOCK_CONFlICT: 175 | Result := Err_LIBSSH2_FX_LOCK_CONFLICT; 176 | LIBSSH2_FX_DIR_NOT_EMPTY: 177 | Result := Err_LIBSSH2_FX_DIR_NOT_EMPTY; 178 | LIBSSH2_FX_NOT_A_DIRECTORY: 179 | Result := Err_LIBSSH2_FX_NOT_A_DIRECTORY; 180 | LIBSSH2_FX_INVALID_FILENAME: 181 | Result := Err_LIBSSH2_FX_INVALID_FILENAME; 182 | LIBSSH2_FX_LINK_LOOP: 183 | Result := Err_LIBSSH2_FX_LINK_LOOP; 184 | else 185 | Result := Err_LIBSSH2_UNKNOWN; 186 | end; 187 | end; 188 | 189 | procedure CheckSftpResult(ReturnCode: Integer; const Op: string); 190 | var 191 | ErrMsg: string; 192 | begin 193 | if ReturnCode < 0 then 194 | begin 195 | // LIBSSH2_ERROR_EAGAIN indicates no result in non-blocking mode 196 | if ReturnCode = LIBSSH2_ERROR_EAGAIN then Exit; 197 | ErrMsg := SftpErrorMsg(ReturnCode); 198 | raise ESftpErr.CreateResFmt(@Err_Sftp, 199 | [ErrMsg, ReturnCode, Op]) 200 | end; 201 | end; 202 | 203 | function TestBit(const ABits, AVal: Cardinal): Boolean; inline; 204 | begin 205 | Result := ABits and AVal { = AVal } <> 0; 206 | end; 207 | function AttrsToFileType(const Attributes: LIBSSH2_SFTP_ATTRIBUTES): TSFTPItemType; 208 | begin 209 | if TestBit(Attributes.Flags, LIBSSH2_SFTP_ATTR_PERMISSIONS) then 210 | begin 211 | case Attributes.Permissions and LIBSSH2_SFTP_S_IFMT of 212 | LIBSSH2_SFTP_S_IFDIR: 213 | Result := sitDirectory; 214 | LIBSSH2_SFTP_S_IFBLK: 215 | Result := sitBlockDev; 216 | LIBSSH2_SFTP_S_IFIFO: 217 | Result := sitFIFO; 218 | LIBSSH2_SFTP_S_IFCHR: 219 | Result := sitCharDev; 220 | LIBSSH2_SFTP_S_IFSOCK: 221 | Result := sitSocket; 222 | LIBSSH2_SFTP_S_IFLNK: 223 | Result := sitSymbolicLink; 224 | LIBSSH2_SFTP_S_IFREG: 225 | Result := sitFile; 226 | else 227 | Result := sitUnknown; 228 | end; 229 | end 230 | else 231 | Result := sitUnknown; 232 | end; 233 | {$endregion} 234 | 235 | {$region TSFtpClient} 236 | type 237 | 238 | TSFtpClient = class(TInterfacedObject, ISftpClient) 239 | private 240 | FSession: ISshSession; 241 | FSftp: PLIBSSH2_SFTP; 242 | FBufferSize: Int64; 243 | FCancelled: Boolean; 244 | FPathDelim: AnsiChar; 245 | FWindowsHost: Boolean; 246 | FTransferCallback: TTransferProgressCallback; 247 | procedure SetBufferSize(Size: Int64); 248 | procedure SetTransferProgressCallback(Callback: TTransferProgressCallback); 249 | procedure RaiseLastSFTPError(Const Op: string); 250 | procedure Cancel; 251 | function SftpType(Name: string; FollowLink: Boolean = True): TSFTPItemType; 252 | function GetPathDelimiter: AnsiChar; 253 | function GetWindowsHost: Boolean; 254 | function ExpandTilde(const S: string): string; 255 | // Directories 256 | function GetCurrentDir: string; 257 | function CreateDir(const Dir: string; Permissions: TFilePermissions = FPDefault): Boolean; 258 | function ForceDirectories(Dir: string): Boolean; 259 | function RemoveDir(const Dir: string): Boolean; 260 | function DirectoryExists(const Directory: string; FollowLink: Boolean = True): Boolean; 261 | function ExcludeTrailingPathDelimiter(const S: string): string; 262 | function IncludeTrailingPathDelimiter(const S: string): string; 263 | function ExtractFileName(const FileName: string): string; 264 | function DirContent(const Dir: string): TSftpItems; 265 | // Files 266 | function FileExists(const FileName: string; FollowLink: Boolean = True): Boolean; 267 | function DeleteFile(const FileName: string): Boolean; 268 | function Rename(const OldName, NewName: string): Boolean; // also works with directories 269 | function ExtractFilePath(const FileName: string): string; 270 | // Symbolic Links 271 | function RealPath(Name: string): string; 272 | function CreateSymLink(const Link, Target: string): Boolean; 273 | // Send and Receive 274 | procedure Receive(const RemoteFile: string; Stream: TStream); overload; 275 | procedure Receive(const RemoteFile, LocalFile: string; Overwrite: Boolean = True); overload; 276 | procedure Send(Stream: TStream; const RemoteFile: string; 277 | Overwrite: Boolean = True; Permissions: TFilePermissions = FPDefault); overload; 278 | procedure Send(const LocalFile, RemoteFile: string; 279 | Overwrite: Boolean = True; Permissions: TFilePermissions = FPDefault); overload; 280 | // Copy Files and Directories 281 | // Source can be a file or a directory and may include a file mask 282 | // Dest is either a file or a directory 283 | procedure CopyToHost(const Source, Dest: string; Recursive: Boolean = True; 284 | Overwrite: Boolean = True; Permissions: TFilePermissions = FPDefault); overload; 285 | procedure CopyFromHost(const Source, Dest: string; Recursive: Boolean = True; 286 | Overwrite: Boolean = True); overload; 287 | public 288 | constructor Create(Session: ISshSession); 289 | destructor Destroy; override; 290 | end; 291 | 292 | { TSFtpClient } 293 | 294 | procedure TSFtpClient.Cancel; 295 | begin 296 | FCancelled := True; 297 | end; 298 | 299 | procedure TSFtpClient.CopyFromHost(const Source, Dest: string; Recursive, 300 | Overwrite: Boolean); 301 | Var 302 | Mask: string; 303 | FilePath: string; 304 | IsFile: Boolean; 305 | IsPath: Boolean; 306 | HasMask: Boolean; 307 | Items: TSftpItems; 308 | Item: TSftpItem; 309 | begin 310 | Mask := ExtractFileName(Source); 311 | HasMask := Mask.IndexOfAny(['?','*']) >= 0; 312 | if HasMask then 313 | begin 314 | IsFile := False; 315 | FilePath := ExtractFilePath(Source); 316 | IsPath := DirectoryExists(FilePath); 317 | end 318 | else 319 | begin 320 | IsFile := FileExists(FilePath, False); 321 | if IsFile then 322 | IsPath := False 323 | else 324 | begin 325 | IsPath := DirectoryExists(Source, False); 326 | FilePath := IncludeTrailingPathDelimiter(Source); 327 | end; 328 | end; 329 | if not (IsFile or IsPath) then 330 | raise ESftpErr.CreateRes(@Err_InvalideSource); 331 | 332 | if IsFile then 333 | Receive(Source, Dest, Overwrite) 334 | else // IsPath 335 | begin 336 | // Dest needs to be a directory - Create if needed 337 | if not System.SysUtils.ForceDirectories(Dest) then 338 | raise ESftpErr.CreateRes(@Err_InvalideDest); 339 | Items := DirContent(FilePath); 340 | for Item in Items do 341 | case Item.ItemType of 342 | sitDirectory: 343 | if Recursive and (Item.FileName <> '.') and (Item.FileName <> '..') then 344 | CopyFromHost(FilePath + Item.FileName, 345 | IncludeTrailingPathDelimiter(Dest) + Item.FileName, 346 | True, Overwrite); 347 | sitFile: 348 | if not HasMask or MatchesMask(Item.FileName, Mask) then 349 | Receive(FilePath + Item.FileName, 350 | System.SysUtils.IncludeTrailingPathDelimiter(Dest) + Item.FileName, 351 | Overwrite); 352 | end; 353 | end; 354 | end; 355 | 356 | procedure TSFtpClient.CopyToHost(const Source, Dest: string; Recursive, 357 | Overwrite: Boolean; Permissions: TFilePermissions); 358 | Var 359 | Mask: string; 360 | FilePath: string; 361 | IsFile: Boolean; 362 | IsPath: Boolean; 363 | HasMask: Boolean; 364 | Files: TStringDynArray; 365 | Dirs: TStringDynArray; 366 | FName: string; 367 | Dir: string; 368 | begin 369 | Mask := System.SysUtils.ExtractFileName(Source); 370 | HasMask := Mask.IndexOfAny(['?','*']) >= 0; 371 | if HasMask then 372 | begin 373 | IsFile := False; 374 | FilePath := System.SysUtils.ExtractFilePath(Source); 375 | IsPath := System.SysUtils.DirectoryExists(FilePath, False); 376 | end 377 | else 378 | begin 379 | IsFile := System.SysUtils.FileExists(FilePath, False); 380 | if IsFile then 381 | IsPath := False 382 | else 383 | begin 384 | IsPath := System.SysUtils.DirectoryExists(Source); 385 | FilePath := System.SysUtils.IncludeTrailingPathDelimiter(Source); 386 | end; 387 | end; 388 | if not (IsFile or IsPath) then 389 | raise ESftpErr.CreateRes(@Err_InvalideSource); 390 | 391 | if IsFile then 392 | Send(Source, Dest, Overwrite, Permissions) 393 | else // IsPath 394 | begin 395 | // Dest needs to be a directory - Create if needed 396 | if not ForceDirectories(Dest) then 397 | raise ESftpErr.CreateRes(@Err_InvalideDest); 398 | Files := TDirectory.GetFiles(FilePath); 399 | for FName in Files do 400 | begin 401 | if not HasMask or MatchesMask(System.SysUtils.ExtractFileName(FName), Mask) then 402 | Send(FName, IncludeTrailingPathDelimiter(Dest) + 403 | System.SysUtils.ExtractFileName(FName), Overwrite, Permissions) 404 | end; 405 | if Recursive then 406 | begin 407 | Dirs := TDirectory.GetDirectories(FilePath); 408 | for Dir in Dirs do 409 | CopyToHost(Dir, IncludeTrailingPathDelimiter(Dest) + System.SysUtils.ExtractFileName(Dir), 410 | True, Overwrite, Permissions); 411 | end; 412 | end; 413 | end; 414 | 415 | constructor TSFtpClient.Create(Session: ISshSession); 416 | begin 417 | inherited Create; 418 | if Session.SessionState <> session_Authorized then 419 | raise ESftpErr.CreateRes(@Err_SessionNotAuth); 420 | FSession := Session; 421 | FWindowsHost := Session.WindowsHost; 422 | if FWindowsHost then 423 | FPathDelim := '\' 424 | else 425 | FPathDelim := '/'; 426 | 427 | FSftp := libssh2_sftp_init(Session.Addr); 428 | FBufferSize := 32 * 1024; 429 | if FSftp = nil then 430 | raise ESftpErr.CreateRes(@Err_SftpInit); 431 | end; 432 | 433 | function TSFtpClient.CreateDir(const Dir: string; Permissions: TFilePermissions): Boolean; 434 | Var 435 | M: TMarshaller; 436 | begin 437 | Result := libssh2_sftp_mkdir(FSFtp, 438 | M.AsAnsi(ExpandTilde(Dir), FSession.CodePage).ToPointer, LongInt(Word(Permissions))) = 0; 439 | end; 440 | 441 | function TSFtpClient.DeleteFile(const FileName: string): Boolean; 442 | Var 443 | M: TMarshaller; 444 | begin 445 | Result := libssh2_sftp_unlink(FSFtp, M.AsAnsi(ExpandTilde(FileName), FSession.CodePage).ToPointer) = 0; 446 | end; 447 | 448 | destructor TSFtpClient.Destroy; 449 | begin 450 | if FSFtp <> nil then 451 | libssh2_sftp_shutdown(FSFtp); 452 | 453 | inherited; 454 | end; 455 | 456 | function ParseItemInfo(AName, ALongEntry: PAnsiChar; CodePage: Word; 457 | Attribs: LIBSSH2_SFTP_ATTRIBUTES): TSftpItem; 458 | begin 459 | Result := Default(TSftpItem); 460 | Result.FileName := AnsiToUnicode(AName, CodePage); 461 | Result.LongEntry := AnsiToUnicode(ALongEntry, CodePage); 462 | Result.ItemType := AttrsToFileType(Attribs); 463 | if TestBit(Attribs.Flags, LIBSSH2_SFTP_ATTR_PERMISSIONS) then 464 | Result.Permissions := TFilePermissions(LongRec(Attribs.permissions).Lo and $01FF); 465 | if TestBit(Attribs.Flags, LIBSSH2_SFTP_ATTR_SIZE) then 466 | Result.FileSize := Attribs.FileSize; 467 | if TestBit(Attribs.Flags, LIBSSH2_SFTP_ATTR_UIDGID) then 468 | begin 469 | Result.UID := Attribs.UID; 470 | Result.GID := Attribs.GID; 471 | end; 472 | if TestBit(Attribs.Flags, LIBSSH2_SFTP_ATTR_ACMODTIME) then 473 | begin 474 | Result.LastAccessTime := UnixToDateTime(Attribs.ATime); 475 | Result.LastModificationTime := UnixToDateTime(Attribs.MTime); 476 | end 477 | end; 478 | 479 | function TSFtpClient.DirContent(const Dir: string): TSftpItems; 480 | const 481 | BUF_LEN = 4 * 1024; 482 | var 483 | EntryBuffer: array [0 .. BUF_LEN - 1] of AnsiChar; 484 | LongEntry: array [0 .. BUF_LEN - 1] of AnsiChar; 485 | DirHandle: PLIBSSH2_SFTP_HANDLE; 486 | List: TList; 487 | Attribs: LIBSSH2_SFTP_ATTRIBUTES; 488 | Count: Integer; 489 | M: TMarshaller; 490 | begin 491 | DirHandle := libssh2_sftp_opendir(FSFtp, M.AsAnsi(RealPath(Dir), 492 | FSession.CodePage).ToPointer); 493 | if DirHandle = nil then 494 | RaiseLastSFTPError('libssh2_sftp_opendir'); 495 | List := TList.Create(TDelegatedComparer.Create( 496 | function(const Left, Right: TSFTPItem): Integer 497 | begin 498 | Result := AnsiCompareStr(Left.FileName, Right.FileName); 499 | end)); 500 | try 501 | FCancelled := False; 502 | repeat 503 | Count := libssh2_sftp_readdir_ex(DirHandle, EntryBuffer, BUF_LEN, 504 | LongEntry, BUF_LEN, @Attribs); 505 | if (Count > 0) then 506 | List.Add(ParseItemInfo(EntryBuffer, LongEntry, FSession.CodePage, Attribs)); 507 | until (Count <= 0) or FCancelled; 508 | List.Sort; 509 | Result := List.ToArray; 510 | finally 511 | List.Free; 512 | libssh2_sftp_closedir(DirHandle); 513 | end; 514 | end; 515 | 516 | function TSFtpClient.DirectoryExists(const Directory: string; 517 | FollowLink: Boolean): Boolean; 518 | begin 519 | try 520 | Result := SftpType(Directory, FollowLink) = sitDirectory; 521 | except 522 | Result := False; 523 | end; 524 | end; 525 | 526 | function TSFtpClient.ExcludeTrailingPathDelimiter(const S: string): string; 527 | begin 528 | Result := S; 529 | if Result[High(Result)] = Char(FPathDelim) then 530 | SetLength(Result, Length(Result)-1); 531 | end; 532 | 533 | function TSFtpClient.ExpandTilde(const S: string): string; 534 | begin 535 | if not FWindowsHost and (Length(S) > 1) and (S[1] = '~') then 536 | Result := '/home/' + FSession.UserName + Copy(S, 2) 537 | else 538 | Result := S; 539 | end; 540 | 541 | function TSFtpClient.ExtractFileName(const FileName: string): string; 542 | var 543 | I: Integer; 544 | Delims: string; 545 | begin 546 | Delims := string(FPathDelim); 547 | if FWindowsHost then 548 | Delims := Delims + DriveDelim; 549 | 550 | I := LastDelimiter(Delims, FileName); 551 | if I >= 0 then 552 | Result := Copy(FileName, I + 2) 553 | else 554 | Result := FileName; 555 | end; 556 | 557 | function TSFtpClient.ExtractFilePath(const FileName: string): string; 558 | var 559 | I: Integer; 560 | Delims: String; 561 | begin 562 | Delims := string(FPathDelim); 563 | if FWindowsHost then 564 | Delims := Delims + DriveDelim; 565 | 566 | I := LastDelimiter(Delims, FileName); 567 | Result := Copy(FileName, 1, I); 568 | end; 569 | 570 | function TSFtpClient.FileExists(const FileName: string; 571 | FollowLink: Boolean): Boolean; 572 | begin 573 | try 574 | Result := SftpType(FileName, FollowLink) in [sitFile, sitSymbolicLink]; 575 | except 576 | Result := False; 577 | end; 578 | end; 579 | 580 | function TSFtpClient.ForceDirectories(Dir: string): Boolean; 581 | begin 582 | Result := True; 583 | if Dir = '' then 584 | raise ESftpErr.CreateRes(@SCannotCreateDir); 585 | 586 | Dir := ExcludeTrailingPathDelimiter(Dir); 587 | if DirectoryExists(Dir) then 588 | Exit; 589 | 590 | if FWindowsHost then 591 | begin 592 | if ((Length(Dir) < 3) or (ExtractFilePath(Dir) = Dir)) then 593 | Exit(CreateDir(Dir)) 594 | end 595 | else 596 | Dir := ExpandTilde(Dir); 597 | Result := ForceDirectories(ExtractFilePath(Dir)) and CreateDir(Dir); 598 | end; 599 | 600 | function TSFtpClient.GetCurrentDir: string; 601 | const 602 | BUF_LEN = 4 * 1024; 603 | var 604 | DirHandle: PLIBSSH2_SFTP_HANDLE; 605 | Buf: PAnsiChar; 606 | begin 607 | Result := ''; 608 | DirHandle := libssh2_sftp_opendir(FSFtp, '.'); 609 | if DirHandle <> nil then 610 | begin 611 | GetMem(Buf, BUF_LEN); 612 | try 613 | libssh2_sftp_realpath(FSFtp, nil, Buf, BUF_LEN); 614 | libssh2_sftp_close(DirHandle); 615 | Result := AnsiToUnicode(Buf, FSession.CodePage); 616 | finally 617 | FreeMem(Buf); 618 | end; 619 | end 620 | else 621 | RaiseLastSftpError('libssh2_sftp_opendir'); 622 | end; 623 | 624 | function TSFtpClient.GetPathDelimiter: AnsiChar; 625 | begin 626 | Result := FPathDelim; 627 | end; 628 | 629 | function TSFtpClient.GetWindowsHost: Boolean; 630 | begin 631 | Result := FWindowsHost; 632 | end; 633 | 634 | function TSFtpClient.IncludeTrailingPathDelimiter(const S: string): string; 635 | begin 636 | Result := S; 637 | if Ord(High(Result)) <> Ord(FPathDelim) then 638 | Result := Result + Char(Ord(FPathDelim)); 639 | end; 640 | 641 | function TSFtpClient.CreateSymLink(const Link, Target: string): Boolean; 642 | Var 643 | M: TMarshaller; 644 | begin 645 | Result := 646 | libssh2_sftp_symlink(FSFtp, M.AsAnsi(RealPath(Target), FSession.CodePage).ToPointer, 647 | M.AsAnsi(ExpandTilde(Link), FSession.CodePage).ToPointer) = 0; 648 | end; 649 | 650 | procedure TSFtpClient.Receive(const RemoteFile: string; Stream: TStream); 651 | var 652 | Attribs: LIBSSH2_SFTP_ATTRIBUTES; 653 | Transfered, Total: UInt64; 654 | FHandle: PLIBSSH2_SFTP_HANDLE; 655 | Buf: PAnsiChar; 656 | R, N: ssize_t; 657 | M: TMarshaller; 658 | begin 659 | FCancelled := False; 660 | CheckSftpResult(libssh2_sftp_stat(FSFtp, 661 | M.AsAnsi(ExpandTilde(RemoteFile), FSession.CodePage).ToPointer, Attribs), 662 | 'libssh2_sftp_stat'); 663 | 664 | if AttrsToFileType(Attribs) <> sitFile then 665 | raise ESftpErr.CreateResFmt(@Err_NotAFile, [RemoteFile]); 666 | 667 | Assert(TestBit(Attribs.Flags, LIBSSH2_SFTP_ATTR_SIZE)); 668 | 669 | FHandle := libssh2_sftp_open(FSftp, 670 | M.AsAnsi(RealPath(RemoteFile), FSession.CodePage).ToPointer, 671 | LIBSSH2_FXF_READ, 0); 672 | if FHandle = nil then 673 | RaiseLastSftpError('libssh2_sftp_open'); 674 | 675 | Total := Attribs.FileSize; 676 | 677 | Transfered := 0; 678 | GetMem(Buf, FBufferSize); 679 | try 680 | repeat 681 | R := libssh2_sftp_read(FHandle, Buf, FBufferSize); 682 | if R > 0 then 683 | begin 684 | N := Stream.Write(Buf^, R); 685 | Assert(N = R); 686 | Inc(Transfered, N); 687 | if Assigned(FTransferCallback) then 688 | FTransferCallback(RemoteFile, Transfered, Total); 689 | end 690 | else if R < 0 then 691 | CheckSftpResult(R, 'libssh2_sftp_read'); 692 | until (R = 0) or FCancelled; 693 | finally 694 | FreeMem(Buf); 695 | libssh2_sftp_close(FHandle); 696 | end; 697 | end; 698 | 699 | procedure TSFtpClient.RaiseLastSFTPError(const Op: string); 700 | begin 701 | CheckSftpResult(libssh2_sftp_last_error(FSftp), Op); 702 | end; 703 | 704 | function TSFtpClient.RealPath(Name: string): string; 705 | const 706 | BUF_LEN = 4 * 1024; 707 | var 708 | Target: array [0 .. BUF_LEN - 1] of AnsiChar; 709 | M: TMarshaller; 710 | begin 711 | Result := ''; 712 | CheckSftpResult(libssh2_sftp_realpath(FSFtp, M.AsAnsi(ExpandTilde(Name), FSession.CodePage).ToPointer, 713 | PAnsiChar(@Target), BUF_LEN), 'libssh2_sftp_realpath'); 714 | Result := AnsiToUnicode(PAnsiChar(@Target), FSession.CodePage); 715 | end; 716 | 717 | procedure TSFtpClient.Receive(const RemoteFile, LocalFile: string; Overwrite:Boolean); 718 | Var 719 | FileStream: TFileStream; 720 | Mode: Word; 721 | begin 722 | if Overwrite then 723 | Mode := fmCreate or fmOpenWrite 724 | else 725 | Mode := fmCreate; 726 | FileStream := TFileStream.Create(LocalFile, Mode); 727 | try 728 | Receive(RemoteFile, FileStream); 729 | finally 730 | FileStream.Free; 731 | end; 732 | end; 733 | 734 | function TSFtpClient.RemoveDir(const Dir: string): Boolean; 735 | Var 736 | M: TMarshaller; 737 | begin 738 | Result := libssh2_sftp_rmdir(FSFtp, M.AsAnsi(ExpandTilde(Dir), FSession.CodePage).ToPointer) = 0; 739 | end; 740 | 741 | function TSFtpClient.Rename(const OldName, NewName: string): Boolean; 742 | var 743 | M: TMarshaller; 744 | begin 745 | Result := libssh2_sftp_rename(FSFtp, 746 | M.AsAnsi(ExpandTilde(OldName), FSession.CodePage).ToPointer, 747 | M.AsAnsi(ExpandTilde(NewName), FSession.CodePage).ToPointer) = 0; 748 | end; 749 | 750 | procedure TSFtpClient.Send(Stream: TStream; const RemoteFile: string; 751 | Overwrite: Boolean; Permissions: TFilePermissions); 752 | var 753 | R, N, K: Integer; 754 | Flags: Integer; 755 | FHandle: PLIBSSH2_SFTP_HANDLE; 756 | Buf, StartBuf: PAnsiChar; 757 | Transfered, Total: UInt64; 758 | M: TMarshaller; 759 | begin 760 | FCancelled := False; 761 | Flags := LIBSSH2_FXF_WRITE or LIBSSH2_FXF_CREAT; 762 | if Overwrite then 763 | Flags := Flags or LIBSSH2_FXF_TRUNC 764 | else 765 | Flags := Flags or LIBSSH2_FXF_EXCL; // ensure call fails if file exists 766 | 767 | FHandle := libssh2_sftp_open(FSFtp, M.AsAnsi(RealPath(RemoteFile), FSession.CodePage).ToPointer, 768 | Flags, LongInt(Word(Permissions))); 769 | if FHandle = nil then 770 | RaiseLastSftpError('libssh2_sftp_open'); 771 | 772 | GetMem(Buf, FBufferSize); 773 | StartBuf := Buf; 774 | Transfered := 0; 775 | Total := Stream.Size - Stream.Position; 776 | try 777 | repeat 778 | N := Stream.Read(Buf^, FBufferSize); 779 | if N > 0 then 780 | begin 781 | K := N; 782 | repeat 783 | R := libssh2_sftp_write(FHandle, Buf, K); 784 | if R < 0 then 785 | CheckSftpResult(R, 'libssh2_sftp_read'); 786 | Inc(Transfered, R); 787 | Inc(Buf, R); 788 | Dec(K, R); 789 | if Assigned(FTransferCallback) then 790 | FTransferCallback(RemoteFile, Transfered, Total); 791 | until (K <= 0) or FCancelled; 792 | Buf := StartBuf; 793 | end; 794 | until (N <= 0) or FCancelled; 795 | finally 796 | FreeMem(StartBuf); 797 | libssh2_sftp_close(FHandle); 798 | end; 799 | end; 800 | 801 | procedure TSFtpClient.Send(const LocalFile, RemoteFile: string; 802 | Overwrite: Boolean; Permissions: TFilePermissions); 803 | Var 804 | FileStream: TFileStream; 805 | begin 806 | FileStream := TFileStream.Create(LocalFile, fmOpenRead); 807 | try 808 | Send(FileStream, RemoteFile, Overwrite, Permissions); 809 | finally 810 | FileStream.Free; 811 | end; 812 | end; 813 | 814 | procedure TSFtpClient.SetBufferSize(Size: Int64); 815 | begin 816 | FBufferSize := Size; 817 | end; 818 | 819 | procedure TSFtpClient.SetTransferProgressCallback( 820 | Callback: TTransferProgressCallback); 821 | begin 822 | FTransferCallback := Callback; 823 | end; 824 | 825 | function TSFtpClient.SftpType(Name: string; FollowLink: Boolean): TSFTPItemType; 826 | var 827 | ReturnCode: integer; 828 | Attribs: LIBSSH2_SFTP_ATTRIBUTES; 829 | M: TMarshaller; 830 | begin 831 | if FollowLink then 832 | ReturnCode := 833 | libssh2_sftp_stat(FSFtp, M.AsAnsi(ExpandTilde(Name), FSession.CodePage).ToPointer, Attribs) 834 | else 835 | ReturnCode := 836 | libssh2_sftp_lstat(FSFtp, M.AsAnsi(ExpandTilde(Name), FSession.CodePage).ToPointer, Attribs); 837 | CheckSftpResult(ReturnCode, 'SftpType'); 838 | Result := AttrsToFileType(Attribs); 839 | end; 840 | {$endregion} 841 | 842 | {$region 'Factory Methods'} 843 | function CreateSftpClient(Session: ISshSession): ISftpClient; 844 | begin 845 | Result := TSFtpClient.Create(Session); 846 | end; 847 | {$endregion} 848 | 849 | end. 850 | -------------------------------------------------------------------------------- /Source/SocketUtils.pas: -------------------------------------------------------------------------------- 1 | unit SocketUtils; 2 | 3 | interface 4 | Uses 5 | WinApi.Windows, 6 | Winapi.WinSock2, 7 | System.SysUtils, 8 | System.RTLConsts; 9 | 10 | type 11 | 12 | ESocketError = class(Exception); 13 | 14 | TIPVersion = (IPvUNSPEC = 0, IPv4 = AF_INET, IPv6 = AF_INET6); 15 | 16 | IWinSock = interface 17 | ['{D2C84E61-0060-475E-9D8C-97EBF6C6AA28}'] 18 | function CreateAndConnectSocket(Host: string; Port: Word; IPVersion: TIPVersion = IPv4): TSocket; 19 | function CreateSocketAndListen(Host: string; Port: Word; 20 | IPVersion: TIPVersion = IPv4; Backlog: Integer = 2): TSocket; 21 | end; 22 | 23 | function GetWinSock: IWinSock; 24 | procedure CheckSocketResult(ResultCode: Integer; const Op: string); 25 | 26 | implementation 27 | 28 | type 29 | PAddrInfoW = ^ADDRINFOW; 30 | ADDRINFOW = record 31 | ai_flags : Integer; // AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST 32 | ai_family : Integer; // PF_xxx 33 | ai_socktype : Integer; // SOCK_xxx 34 | ai_protocol : Integer; // 0 or IPPROTO_xxx for IPv4 and IPv6 35 | ai_addrlen : size_t; // Length of ai_addr 36 | ai_canonname : PWideChar; // Canonical name for nodename 37 | ai_addr : PSOCKADDR; // Binary address 38 | ai_next : PAddrInfoW; // Next structure in linked list 39 | end; 40 | TAddrInfoW = ADDRINFOW; 41 | 42 | {$WARN SYMBOL_PLATFORM OFF} 43 | function GetAddrInfoW(NodeName: PWideChar; ServiceName: PWideChar; 44 | Hints: PaddrinfoW; var pResult: PaddrinfoW): Integer; stdcall; 45 | external 'ws2_32.dll' name 'GetAddrInfoW' delayed; 46 | procedure FreeAddrInfoW(ai: PaddrinfoW); stdcall; 47 | external 'ws2_32.dll' name 'FreeAddrInfoW' delayed; 48 | {$WARN SYMBOL_PLATFORM ON} 49 | 50 | procedure StartWinSock; 51 | var 52 | Data: WSAData; 53 | ErrorCode: Integer; 54 | begin 55 | ErrorCode := WSAStartup(WINSOCK_VERSION, Data); 56 | if ErrorCode <> 0 then 57 | raise ESocketError.CreateResFmt(@sWindowsSocketError, 58 | [SysErrorMessage(ErrorCode), ErrorCode, 'WSAStartup']); 59 | end; 60 | 61 | type 62 | TWinSock = class(TInterfacedObject, IWinSock) 63 | class var FInstanceCount: Integer; 64 | private 65 | function CreateAndConnectSocket(Host: string; Port: Word; IPVersion: TIPVersion = IPv4): TSocket; 66 | function CreateSocketAndListen(Host: string; Port: Word; 67 | IPVersion: TIPVersion = IPv4; Backlog: Integer = 2): TSocket; 68 | function CreateSocket(Host: string; Port: Word; IPVersion: TIPVersion; var AddrInfo: PAddrInfoW): TSocket; 69 | public 70 | constructor Create; 71 | destructor Destroy; override; 72 | end; 73 | 74 | function GetWinSock: IWinSock; 75 | begin 76 | Result := TWinSock.Create; 77 | end; 78 | 79 | procedure CheckSocketResult(ResultCode: Integer; const Op: string); 80 | begin 81 | if ResultCode <> 0 then 82 | begin 83 | if ResultCode <> WSAEWOULDBLOCK then 84 | raise ESocketError.CreateResFmt(@sWindowsSocketError, 85 | [SysErrorMessage(ResultCode), ResultCode, Op]); 86 | end; 87 | end; 88 | 89 | { TWinSock } 90 | 91 | function TWinSock.CreateAndConnectSocket(Host: string; Port: Word; IPVersion: TIPVersion = IPv4): TSocket; 92 | Var 93 | AddrInfo: PaddrinfoW; 94 | ReturnCode : Integer; 95 | begin 96 | AddrInfo := nil; 97 | Result := CreateSocket(Host, Port, IPVersion, AddrInfo); 98 | 99 | try 100 | ReturnCode := 0; 101 | while AddrInfo <> nil do 102 | begin 103 | ReturnCode := connect(Result, AddrInfo^.ai_addr^, AddrInfo^.ai_addrlen); 104 | if ReturnCode = 0 then break; 105 | AddrInfo := AddrInfo^.ai_next; 106 | end; 107 | CheckSocketResult(ReturnCode, 'connect'); 108 | finally 109 | if AddrInfo <> nil then FreeAddrInfoW(AddrInfo); 110 | end; 111 | end; 112 | 113 | function TWinSock.CreateSocketAndListen(Host: string; Port: Word; 114 | IPVersion: TIPVersion; Backlog: Integer): TSocket; 115 | Var 116 | AddrInfo: PaddrinfoW; 117 | ReturnCode : Integer; 118 | begin 119 | AddrInfo := nil; 120 | Result := CreateSocket(Host, Port, IPVersion, AddrInfo); 121 | 122 | try 123 | ReturnCode := 0; 124 | while AddrInfo <> nil do 125 | begin 126 | ReturnCode := bind(Result, AddrInfo^.ai_addr^, AddrInfo^.ai_addrlen); 127 | if ReturnCode = 0 then break; 128 | AddrInfo := AddrInfo^.ai_next; 129 | end; 130 | CheckSocketResult(ReturnCode, 'bind'); 131 | CheckSocketResult(listen(Result, 2), 'listen'); 132 | finally 133 | if AddrInfo <> nil then FreeAddrInfoW(AddrInfo); 134 | end; 135 | end; 136 | 137 | 138 | constructor TWinSock.Create; 139 | begin 140 | inherited; 141 | if AtomicIncrement(FInstanceCount) = 1 then 142 | StartWinSock; 143 | end; 144 | 145 | destructor TWinSock.Destroy; 146 | begin 147 | if AtomicDecrement(FInstanceCount) = 0 then 148 | WSACleanup; 149 | inherited; 150 | end; 151 | 152 | function TWinSock.CreateSocket(Host: string; Port: Word; 153 | IPVersion: TIPVersion; var AddrInfo: PAddrInfoW): TSocket; 154 | var 155 | Hints: TAddrInfoW; 156 | begin 157 | Result := socket(Ord(IpVersion), SOCK_STREAM, IPPROTO_TCP); 158 | if Result = INVALID_SOCKET then 159 | CheckSocketResult(WSAGetLastError, 'socket'); 160 | FillChar(Hints, sizeof(Hints), 0); 161 | Hints.ai_family := Ord(IpVersion); 162 | Hints.ai_socktype := SOCK_STREAM; 163 | Hints.ai_protocol := IPPROTO_TCP; 164 | CheckSocketResult(GetaddrinfoW(PChar(Host), PChar(Port.ToString), @Hints, AddrInfo), 'GetaddrinfoW'); 165 | end; 166 | 167 | end. 168 | 169 | -------------------------------------------------------------------------------- /Source/Ssh2Client.pas: -------------------------------------------------------------------------------- 1 | unit Ssh2Client; 2 | { 3 | 4 | Copyright (c) 2020 Kiriakos Vlahos (PyScripter) 5 | Delphi wrapper of libssh2 (https://www.libssh2.org/) 6 | 7 | The C header translation and the SFTP implementation draw from 8 | https://bitbucket.org/ZeljkoMarjanovic/libssh2-delphi 9 | Copyright (c) 2010, Zeljko Marjanovic (MPL 1.1) 10 | 11 | Released under the MIT Licence 12 | } 13 | 14 | interface 15 | uses 16 | WinApi.Windows, 17 | WinApi.Winsock2, 18 | System.SysUtils, 19 | System.Classes, 20 | SocketUtils, 21 | libssh2; 22 | 23 | type 24 | ESshError = class(Exception); 25 | // Used for user input (password entry, known host verification) 26 | // If Echo is False the response should be masked 27 | TKeybInteractiveCallback = function(const AuthName, AuthInstruction, Prompt: string; 28 | Echo: Boolean): string; 29 | TKeybInteractiveCallbackMethod = function(const AuthName, AuthInstruction, Prompt: string; 30 | Echo: Boolean): string of object; 31 | TTransferProgressCallback = procedure(const AFileName: string; ATransfered, ATotal: UInt64); 32 | 33 | TAuthMethod = (amInteractive, amPassword, amKey, amHostBased); 34 | TAuthMethods = set of TAuthMethod; 35 | 36 | TSessionState = (session_Disconnected, session_Connected, session_Authorized); 37 | 38 | //KwonHost related 39 | TKnownHostCheckState = (khcsMatch, khcsMisMatch, khcsNotFound, khcsFailure); 40 | TKnownHostCheckAction = (khcaContinue, khcaStop, khcaAsk); 41 | TKnownHostCheckPolicy = array [TKnownHostCheckState] of TKnownHostCheckAction; 42 | var 43 | DefKnownHostCheckPolicy: TKnownHostCheckPolicy = (khcaContinue, khcaAsk, khcaAsk, khcaAsk); 44 | 45 | type 46 | TFilePermission = (fpOtherExec, fpOtherWrite, fpOtherRead, 47 | fpGroupExec, fpGroupWrite, fpGroupRead, 48 | fpUserExec, fpUserWrite, fpUserRead); 49 | TFilePermissions = set of TFilePermission; 50 | 51 | const 52 | FPAllUser = [fpUserRead, fpUserWrite, fpUserExec]; 53 | FPAllGroup = [fpGroupRead, fpGroupWrite, fpGroupExec]; 54 | FPAllOther = [fpOtherRead, fpOtherWrite, fpOtherExec]; 55 | FPDefault = FPAllUser + [fpGroupRead, fpGroupExec, fpOtherRead, fpOtherExec]; 56 | 57 | type 58 | ILibSsh2 = interface 59 | ['{EF87E36A-957B-49CA-9680-FEFBF1CE92B2}'] 60 | function GetVersion: string; 61 | property Version: string read GetVersion; 62 | end; 63 | 64 | ISshSession = interface 65 | ['{D1921C45-7838-4E30-B511-6C4AE6C6E4DC}'] 66 | function GetAddr: PLIBSSH2_SESSION; 67 | function GetSocket: TSocket; 68 | function GetSessionState: TSessionState; 69 | function GetBlocking: Boolean; 70 | procedure SetBlocking(Block: Boolean); 71 | procedure SetUseCompression(Compress: Boolean); 72 | function GetHostBanner: string; 73 | function GetSessionMethods: string; 74 | function GetWindowsHost: Boolean; 75 | function GetCodePage: Word; 76 | procedure SetCodePage(const CP: Word); 77 | procedure SetKeybInteractiveCallback(Callback: TKeybInteractiveCallback); 78 | procedure SetKeybInteractiveCallbackMethod(Callback: TKeybInteractiveCallbackMethod); 79 | procedure ConfigKeepAlive(WantServerReplies: Boolean; IntervalInSecs: Cardinal); 80 | procedure ConfigKnownHostCheckPolicy(EnableCheck: Boolean; 81 | const Policy: TKnownHostCheckPolicy; const KnownHostsFile: string = ''); 82 | procedure Connect(UseDefaultMem: Boolean = False; IPVersion: TIPVersion = IPv4); 83 | procedure Disconnect; 84 | function AuthMethods(UserName: string): TAuthMethods; 85 | { 86 | UserAuth tries None, Agent, Interactive and Password authorizations. 87 | For the latter two the KeybInteractiveCallback needs to be set 88 | } 89 | function UserAuth(const UserName: string): Boolean; 90 | function UserAuthBanner: string; 91 | function UserAuthNone(const UserName: string): Boolean; 92 | function UserAuthPass(const UserName, Password: string): Boolean; 93 | function UserAuthInteractive(const UserName: string): Boolean; 94 | // Uses TKeybInteractiveCallback (needs to be set) to get the passphrase 95 | function UserAuthKey(const UserName, PublicKeyFile, PrivateKeyFile: string): Boolean; overload; 96 | // PassPhrase can be '' 97 | function UserAuthKey(const UserName, PublicKeyFile, PrivateKeyFile, PassPhrase: string): Boolean; overload; 98 | function UserAuthAgent(const UserName: string): Boolean; 99 | function GetUserName: string; 100 | // Set timeout for blocking functions 101 | // - aTimeoutInMs: Timeout in milliseconds. 102 | procedure SetTimeout(aTimeoutInMs: LongInt); 103 | procedure Trace(BitMask: Integer); 104 | property Addr: PLIBSSH2_SESSION read GetAddr; 105 | property SessionState: TSessionState read GetSessionState; 106 | property Blocking: Boolean read GetBlocking write SetBlocking; 107 | property UseCompression: Boolean write SetUseCompression; 108 | property HostBanner: string read GetHostBanner; 109 | property WindowsHost: Boolean read GetWindowsHost; 110 | property SessionMethods: string read GetSessionMethods; 111 | { The host code page. Default CP_UTF8} 112 | property CodePage: Word read GetCodePage write SetCodePage; 113 | property UserName: string read GetUserName; 114 | property Socket: TSocket read GetSocket; 115 | end; 116 | 117 | type 118 | IScp = interface 119 | ['{A780AD77-2D29-499F-8062-B1B18F9E55A8}'] 120 | procedure SetBufferSize(Size: Int64); 121 | procedure SetTransferProgressCallback(Callback: TTransferProgressCallback); 122 | procedure Cancel; 123 | procedure Receive(const RemoteFile: string; Stream: TStream); overload; 124 | procedure Receive(const RemoteFile, LocalFile: string); overload; 125 | procedure Send(Stream: TStream; const RemoteFile: string; 126 | Permissions: TFilePermissions = FPDefault; 127 | MTime: TDateTime = 0; ATime: TDateTime = 0); overload; 128 | procedure Send(const LocalFile, RemoteFile: string; 129 | Permissions: TFilePermissions = FPDefault; 130 | MTime: TDateTime = 0; ATime: TDateTime = 0); overload; 131 | property BufferSize: Int64 write SetBufferSize; 132 | end; 133 | 134 | { Execute commands on the host and get Output/Errorcode back } 135 | ISshExec = interface 136 | ['{CA97A730-667A-4800-AF5D-77D5A4DDB192}'] 137 | procedure SetBufferSize(Size: Int64); 138 | procedure Cancel; 139 | procedure Exec(const Command: string; var Output, ErrOutput: string; var ExitCode: Integer); 140 | property BufferSize: Int64 write SetBufferSize; 141 | end; 142 | 143 | // Factory functions 144 | function GetLibSsh2: ILibSsh2; 145 | function CreateSession(Host: string; Port: Word = 22): ISshSession; 146 | function CreateScp(Session: ISshSession): IScp; 147 | function CreateSshExec(Session: ISshSession): ISshExec; 148 | 149 | // support routines 150 | function AnsiToUnicode(P: PAnsiChar; CP: Word): string; overload; 151 | function AnsiToUnicode(P: PAnsiChar; Len: Int64; CP: Word): string; overload; 152 | procedure CheckLibSsh2Result(ResultCode: Integer; Session: ISshSession; const Op: string); 153 | 154 | var 155 | // Default timeout in milliseconds for block functions 156 | gDefaultSshTimeout: Integer = 30000; 157 | 158 | implementation 159 | 160 | uses 161 | System.Math, 162 | System.AnsiStrings, 163 | System.DateUtils; 164 | 165 | {$region 'Support stuff'} 166 | resourcestring 167 | Err_LibSsh2 = 'LibSSh2 error: %s (%d), on API "%s"'; 168 | Err_SessionInit = 'LibSsh2 error: Failed to initialize session'; 169 | Err_SessionAuth = 'LibSsh2 session is not connected and authorised'; 170 | Err_SessionUnKnownHost = 'The authenticity of host "%s" can''t be established.'; 171 | UnKnownHostPrompt = 'Do you want to continue connecting (yes/no)?'; 172 | Msg_Disconnect = 'Bye'; 173 | Msg_Password = 'Password: '; 174 | Msg_PassPhrase = 'Passphrase: '; 175 | Msg_PrivateKeyInstruction = 'Private key password for "%s"'; 176 | 177 | function AnsiToUnicode(P: PAnsiChar; CP: Word): string; 178 | Var 179 | S: RawByteString; 180 | begin 181 | if P = nil then Exit(''); 182 | 183 | S:= P; 184 | SetCodePage(S, CP, False); 185 | Result := string(S); 186 | end; 187 | 188 | function AnsiToUnicode(P: PAnsiChar; Len: Int64; CP: Word): string; 189 | Var 190 | S: RawByteString; 191 | begin 192 | if P = nil then Exit(''); 193 | 194 | SetString(S, P, Len); 195 | SetCodePage(S, CP, False); 196 | Result := string(S); 197 | end; 198 | 199 | procedure CheckLibSsh2Result(ResultCode: Integer; Session: ISshSession; const Op: string); 200 | var 201 | I: Integer; 202 | P: PAnsiChar; 203 | ErrMsg: string; 204 | begin 205 | if ResultCode < 0 then 206 | begin 207 | if Session <> nil then 208 | begin 209 | // LIBSSH2_ERROR_EAGAIN indicates no result in non-blocking mode 210 | if ResultCode = LIBSSH2_ERROR_EAGAIN then Exit; 211 | libssh2_session_last_error(Session.Addr, P, I, 0); 212 | ErrMsg := AnsiToUnicode(P, I, Session.CodePage); 213 | end; 214 | raise ESshError.CreateResFmt(@Err_LibSsh2, 215 | [ErrMsg, ResultCode, Op]) 216 | end; 217 | end; 218 | {$endregion} 219 | 220 | {$region 'TLibSSh2'} 221 | type 222 | TLibSSh2 = class(TInterfacedObject, ILibSsh2) 223 | private 224 | class var FInstanceCount: Integer; 225 | function GetVersion: string; 226 | public 227 | constructor Create; 228 | destructor Destroy; override; 229 | end; 230 | 231 | { TLibSSh2 } 232 | 233 | constructor TLibSSh2.Create; 234 | begin 235 | inherited; 236 | if AtomicIncrement(FInstanceCount) = 1 then 237 | CheckLibSsh2Result(libssh2_init(0), nil, 'libssh2_init'); 238 | end; 239 | 240 | destructor TLibSSh2.Destroy; 241 | begin 242 | if AtomicDecrement(FInstanceCount) = 0 then 243 | libssh2_exit(); 244 | inherited; 245 | end; 246 | 247 | function TLibSSh2.GetVersion: string; 248 | begin 249 | Result := string(libssh2_version(0)); 250 | end; 251 | {$endregion} 252 | 253 | {$region 'TSshSession'} 254 | type 255 | TKnownHostCheckSettings = record 256 | EnableCheck: Boolean; 257 | Policy: TKnownHostCheckPolicy; 258 | KnownHostsFile: string; 259 | end; 260 | 261 | TSshSession = class(TInterfacedObject, ISshSession) 262 | private 263 | FState: TSessionState; 264 | FWinSock: IWinSock; 265 | FLibSsh2: ILibSsh2; 266 | FSock: TSocket; 267 | FAddr: PLIBSSH2_SESSION; 268 | FHost: string; 269 | FPort: Word; 270 | FUserName: string; 271 | FCompression: Boolean; 272 | FCodePage: Word; 273 | FAuthMethods: TAuthMethods; 274 | FAuthMethodsCached: Boolean; 275 | FKnownHostCheckSettings: TKnownHostCheckSettings; 276 | FKeybIntEventFunction: TKeybInteractiveCallback; 277 | FKeybIntEventMethod: TKeybInteractiveCallbackMethod; 278 | function HasKeybIntEvent: boolean; 279 | function doKeybInt(const AuthName, AuthInstruction, Prompt: string; Echo: Boolean): string; 280 | function GetAddr: PLIBSSH2_SESSION; 281 | function GetSocket: TSocket; 282 | function GetSessionState: TSessionState; 283 | function GetBlocking: Boolean; 284 | procedure SetBlocking(Block: Boolean); 285 | procedure SetUseCompression(Compress: Boolean); 286 | function GetHostBanner: string; 287 | function GetSessionMethods: string; 288 | function GetWindowsHost: Boolean; 289 | function GetCodePage: Word; 290 | procedure SetCodePage(const CP: Word); 291 | procedure SetKeybInteractiveCallback(Callback: TKeybInteractiveCallback); 292 | procedure SetKeybInteractiveCallbackMethod(Callback: TKeybInteractiveCallbackMethod); 293 | procedure ConfigKeepAlive(WantServerReplies: Boolean; IntervalInSecs: Cardinal); 294 | procedure ConfigKnownHostCheckPolicy(EnableCheck: Boolean; 295 | const Policy: TKnownHostCheckPolicy; const KnownHostsFile: string = ''); 296 | procedure Connect(UseDefaultMem: Boolean = False; IPVersion: TIPVersion = IPv4); 297 | procedure CheckKnownHost; 298 | function AuthMethods(UserName: string): TAuthMethods; 299 | function UserAuth(const UserName: string): Boolean; 300 | function UserAuthBanner: string; 301 | function UserAuthNone(const UserName: string): Boolean; 302 | function UserAuthPass(const UserName, Password: string): Boolean; 303 | function UserAuthInteractive(const UserName: string): Boolean; 304 | function UserAuthKey(const UserName, PublicKeyFile, PrivateKeyFile: string): Boolean; overload; 305 | function UserAuthKey(const UserName, PublicKeyFile, PrivateKeyFile, PassPhrase: string): Boolean; overload; 306 | function UserAuthAgent(const UserName: string): Boolean; 307 | function GetUserName: string; 308 | procedure Disconnect; 309 | // Set timeout for blocking functions 310 | // - aTimeoutInMs: Timeout in milliseconds. 311 | procedure SetTimeout(aTimeoutInMs: LongInt); 312 | procedure Trace(BitMask: Integer); 313 | public 314 | constructor Create(Host: string; Port: Word); 315 | destructor Destroy; override; 316 | end; 317 | 318 | { ----------------------------------------------------- } 319 | { Memory } 320 | { ----------------------------------------------------- } 321 | 322 | function malloc(size: size_t; abstract: PPointer): Pointer; cdecl; 323 | begin 324 | Result := AllocMem(size); 325 | end; 326 | 327 | function realloc(P: Pointer; NewSize: size_t; abstract: PPointer): Pointer; cdecl; 328 | begin 329 | ReallocMem(P, Newsize); 330 | Result := P; 331 | end; 332 | 333 | procedure mfree(pBlock: Pointer; abstract: PPointer); cdecl; 334 | begin 335 | FreeMem(pBlock); 336 | end; 337 | 338 | { TSshSession } 339 | 340 | function TSshSession.doKeybInt(const AuthName, AuthInstruction, Prompt: string; Echo: Boolean): string; 341 | begin 342 | if Assigned(FKeybIntEventFunction) then 343 | Result := FKeybIntEventFunction(AuthName, AuthInstruction, Prompt, Echo) 344 | else if Assigned(FKeybIntEventMethod) then 345 | Result := FKeybIntEventMethod(AuthName, AuthInstruction, Prompt, Echo) 346 | else 347 | raise ESshError.Create('Neither FKeybIntEventFunction nor FKeybIntEventMethod is assigned'); 348 | end; 349 | 350 | procedure TSshSession.CheckKnownHost; 351 | Var 352 | KnownHosts: PLIBSSH2_KNOWNHOSTS; 353 | ReturnCode: integer; 354 | M: TMarshaller; 355 | FingerPrint: PAnsiChar; 356 | KeyLen: NativeUInt; 357 | Typ: Integer; 358 | HostResult: PLIBSSH2_KNOWNHOST; 359 | Handle: THandle; 360 | 361 | procedure HandleState(State: TKnownHostCheckState); 362 | var 363 | Action: TKnownHostCheckAction; 364 | begin 365 | Action := FKnownHostCheckSettings.Policy[State]; 366 | if (Action = khcaAsk) then 367 | begin 368 | if not HasKeybIntEvent then begin 369 | Action := khcaStop 370 | end else begin 371 | if doKeybInt('', Format(Err_SessionUnKnownHost, [FHost]), 372 | UnKnownHostPrompt, True) = 'yes' then 373 | Action := khcaContinue 374 | else 375 | Action := khcaStop; 376 | end; 377 | end; 378 | if (Action = khcaContinue) and Assigned(KnownHosts) and Assigned(Fingerprint) then 379 | begin 380 | if libssh2_knownhost_addc(KnownHosts, M.AsAnsi(FHost, FCodePage).ToPointer, nil, FingerPrint, 381 | Keylen, nil, 0, LIBSSH2_KNOWNHOST_TYPE_PLAIN or LIBSSH2_KNOWNHOST_KEYENC_RAW 382 | // LIBSSH2_HOSTKEY_TYPE_ -> LIBSSH2_KNOWNHOST_KEY_ 383 | or (Succ(typ) shl LIBSSH2_KNOWNHOST_KEY_SHIFT), HostResult) = 0 384 | then 385 | libssh2_knownhost_writefile(KnownHosts, 386 | M.AsAnsi(FKnownHostCheckSettings.KnownHostsFile, FCodePage).ToPointer, 387 | LIBSSH2_KNOWNHOST_FILE_OPENSSH); 388 | end; 389 | if Action = khcaStop then 390 | raise Exception.CreateResFmt(@Err_SessionUnKnownHost, [FHost]); 391 | end; 392 | 393 | begin 394 | KnownHosts := nil; 395 | FingerPrint := nil; 396 | if not FileExists(FKnownHostCheckSettings.KnownHostsFile) then 397 | begin 398 | Handle := FileCreate(FKnownHostCheckSettings.KnownHostsFile); 399 | if Handle = INVALID_HANDLE_VALUE then 400 | begin 401 | HandleState(khcsFailure); 402 | Exit; 403 | end 404 | else 405 | FileClose(Handle); 406 | end; 407 | 408 | Fingerprint := libssh2_session_hostkey(FAddr, KeyLen, Typ); 409 | if FingerPrint = nil then 410 | begin 411 | HandleState(khcsFailure); 412 | Exit; 413 | end; 414 | 415 | KnownHosts := libssh2_knownhost_init(FAddr); 416 | if KnownHosts = nil then 417 | begin 418 | HandleState(khcsFailure); 419 | Exit; 420 | end; 421 | 422 | try 423 | ReturnCode := libssh2_knownhost_readfile(KnownHosts, 424 | M.AsAnsi(FKnownHostCheckSettings.KnownHostsFile, FCodePage).ToPointer, 425 | LIBSSH2_KNOWNHOST_FILE_OPENSSH); 426 | if ReturnCode < 0 then 427 | HandleState(khcsFailure) 428 | else if ReturnCode = 0 then 429 | HandleState(khcsNotFound); 430 | if ReturnCode <= 0 then 431 | Exit; 432 | 433 | ReturnCode := libssh2_knownhost_checkp(KnownHosts, M.AsAnsi(FHost, FCodePage).ToPointer, 434 | FPort, Fingerprint, KeyLen, LIBSSH2_KNOWNHOST_TYPE_PLAIN or 435 | LIBSSH2_KNOWNHOST_KEYENC_RAW, HostResult); 436 | 437 | if ReturnCode <> LIBSSH2_KNOWNHOST_CHECK_MATCH then 438 | HandleState(TKnownHostCheckState(ReturnCode)); 439 | 440 | finally 441 | libssh2_knownhost_free(KnownHosts); 442 | end; 443 | end; 444 | 445 | procedure TSshSession.ConfigKeepAlive(WantServerReplies: Boolean; 446 | IntervalInSecs: Cardinal); 447 | {Note that non-blocking applications are responsible for sending the 448 | keepalive messages using libssh2_keepalive_sendbegin} 449 | begin 450 | libssh2_keepalive_config(FAddr, IfThen(WantServerReplies, 1, 0), IntervalInSecs); 451 | end; 452 | 453 | procedure TSshSession.ConfigKnownHostCheckPolicy(EnableCheck: Boolean; 454 | const Policy: TKnownHostCheckPolicy; const KnownHostsFile: string); 455 | begin 456 | FKnownHostCheckSettings.EnableCheck := EnableCheck; 457 | if KnownHostsFile <> '' then 458 | FKnownHostCheckSettings.KnownHostsFile := KnownHostsFile; 459 | FKnownHostCheckSettings.Policy := Policy; 460 | end; 461 | 462 | procedure TSshSession.Connect(UseDefaultMem: Boolean = False; 463 | IPVersion: TIPVersion = IPv4); 464 | begin 465 | FSock := FWinSock.CreateAndConnectSocket(FHost, FPort, IPVersion); 466 | if UseDefaultMem then 467 | FAddr := libssh2_session_init_ex(nil, nil, nil, Pointer(Self)) 468 | else 469 | FAddr := libssh2_session_init_ex(malloc, mfree, realloc, Pointer(Self)); 470 | if Faddr = nil then 471 | raise ESshError.CreateRes(@Err_SessionInit); 472 | libssh2_session_flag(FAddr, LIBSSH2_FLAG_COMPRESS, IfThen(FCompression, 1, 0)); 473 | 474 | // libssh2_session_method_pref(FAddr, LIBSSH2_METHOD_KEX, 'curve25519-sha256'); 475 | // libssh2_session_method_pref(FAddr, LIBSSH2_METHOD_CRYPT_CS, 'aes256-ctr'); 476 | // libssh2_session_method_pref(FAddr, LIBSSH2_METHOD_CRYPT_SC, 'aes256-ctr'); 477 | // libssh2_session_method_pref(FAddr, LIBSSH2_METHOD_MAC_CS, 'hmac-sha2-512'); 478 | // libssh2_session_method_pref(FAddr, LIBSSH2_METHOD_MAC_SC, 'hmac-sha2-512'); 479 | // libssh2_session_method_pref(FAddr, LIBSSH2_METHOD_LANG_CS, 'en-US'); 480 | // libssh2_session_method_pref(FAddr, LIBSSH2_METHOD_LANG_SC, 'en-US'); 481 | 482 | CheckLibSsh2Result( 483 | libssh2_session_handshake(FAddr, FSock), 484 | Self as TSshSession, 'libssh2_session_handshake'); 485 | SetBlocking(True); // blocking by default 486 | FState := session_Connected; 487 | SetTimeout(gDefaultSshTimeout); 488 | 489 | if FKnownHostCheckSettings.EnableCheck then 490 | try 491 | CheckKnownHost; 492 | except 493 | Disconnect; 494 | raise 495 | end; 496 | end; 497 | 498 | constructor TSshSession.Create(Host: string; Port: Word); 499 | function ExpandEnvStrings(const AString: String): String; 500 | var 501 | bufsize: Integer; 502 | begin 503 | bufsize := ExpandEnvironmentStrings(PChar(AString), nil, 0); 504 | SetLength(result, bufsize); 505 | ExpandEnvironmentStrings(PChar(AString), PChar(result), bufsize); 506 | result := TrimRight(result); 507 | end; 508 | begin 509 | inherited Create; 510 | FKnownHostCheckSettings.EnableCheck := True; 511 | FKnownHostCheckSettings.Policy := DefKnownHostCheckPolicy; 512 | FKnownHostCheckSettings.KnownHostsFile := ExpandEnvStrings( 513 | IncludeTrailingPathDelimiter('%USERPROFILE%') + '.ssh\known_hosts'); 514 | FWinSock := GetWinSock; 515 | FLibSsh2 := GetLibSsh2; 516 | FHost := Host; 517 | FPort := Port; 518 | FCodePage := CP_UTF8; 519 | FSock := INVALID_SOCKET; 520 | end; 521 | 522 | destructor TSshSession.Destroy; 523 | begin 524 | Disconnect; 525 | FLibSsh2 := nil; 526 | FWinSock := nil; 527 | inherited; 528 | end; 529 | 530 | procedure TSshSession.Disconnect; 531 | var 532 | M: TMarshaller; 533 | begin 534 | if FAddr <> nil then 535 | begin 536 | libssh2_session_disconnect(FAddr, M.AsAnsi(Msg_Disconnect, FCodePage).ToPointer); 537 | libssh2_session_free(FAddr); 538 | end; 539 | FAddr := nil; 540 | if FSock <> INVALID_SOCKET then 541 | closesocket(FSock); 542 | FSock := INVALID_SOCKET; 543 | FState := session_Disconnected; 544 | end; 545 | 546 | function TSshSession.GetAddr: PLIBSSH2_SESSION; 547 | begin 548 | Result := FAddr; 549 | end; 550 | 551 | function TSshSession.GetBlocking: Boolean; 552 | begin 553 | Result := libssh2_session_get_blocking(FAddr) <> 0; 554 | end; 555 | 556 | function TSshSession.GetCodePage: Word; 557 | begin 558 | Result := FCodePage; 559 | end; 560 | 561 | function TSshSession.GetHostBanner: string; 562 | var 563 | S: RawByteString; 564 | begin 565 | S := libssh2_session_banner_get(FAddr); 566 | System.SetCodePage(S, FCodePage, False); 567 | Result := string(S); 568 | end; 569 | 570 | function TSshSession.GetSessionMethods: string; 571 | begin 572 | Result := ''; 573 | if FAddr <> nil then 574 | Result := Format('KEX: %s, CRYPT: %s, MAC: %s, COMP: %s, LANG: %s', 575 | [libssh2_session_methods(FAddr, LIBSSH2_METHOD_KEX), libssh2_session_methods(FAddr, 576 | LIBSSH2_METHOD_CRYPT_CS), libssh2_session_methods(FAddr, LIBSSH2_METHOD_MAC_CS), 577 | libssh2_session_methods(FAddr, LIBSSH2_METHOD_COMP_CS) + ' ' + 578 | libssh2_session_methods(FAddr, LIBSSH2_METHOD_COMP_SC), 579 | libssh2_session_methods(FAddr, LIBSSH2_METHOD_LANG_CS)]); 580 | end; 581 | 582 | function TSshSession.GetSessionState: TSessionState; 583 | begin 584 | Result := FState; 585 | end; 586 | 587 | function TSshSession.GetSocket: TSocket; 588 | begin 589 | Result := FSock; 590 | end; 591 | 592 | function TSshSession.GetUserName: string; 593 | begin 594 | Result := FUserName; 595 | end; 596 | 597 | function TSshSession.GetWindowsHost: Boolean; 598 | begin 599 | Result := Pos('Windows', GetHostBanner) > 0; 600 | end; 601 | 602 | function TSshSession.HasKeybIntEvent: boolean; 603 | begin 604 | Result := Assigned(FKeybIntEventFunction) or Assigned(FKeybIntEventMethod); 605 | end; 606 | 607 | procedure TSshSession.SetBlocking(Block: Boolean); 608 | begin 609 | libssh2_session_set_blocking(Faddr, IfThen(Block, 1, 0)) 610 | end; 611 | 612 | procedure TSshSession.SetCodePage(const CP: Word); 613 | begin 614 | FCodePage := CP; 615 | end; 616 | 617 | procedure TSshSession.SetKeybInteractiveCallback(Callback: TKeybInteractiveCallback); 618 | begin 619 | FKeybIntEventFunction := Callback; 620 | end; 621 | 622 | procedure TSshSession.SetKeybInteractiveCallbackMethod(Callback: TKeybInteractiveCallbackMethod); 623 | begin 624 | FKeybIntEventMethod := Callback; 625 | end; 626 | 627 | procedure TSshSession.SetUseCompression(Compress: Boolean); 628 | begin 629 | FCompression := Compress; 630 | end; 631 | 632 | procedure TSshSession.Trace(BitMask: Integer); 633 | begin 634 | CheckLibSsh2Result(libssh2_trace(FAddr, BitMask), 635 | Self, 'libssh2_trace'); 636 | end; 637 | 638 | function TSshSession.AuthMethods(UserName: string): TAuthMethods; 639 | var 640 | M: TMarshaller; 641 | PList: PAnsiChar; 642 | List: string; 643 | begin 644 | if FAuthMethodsCached then Exit(FAuthMethods); 645 | 646 | FAuthMethods := []; 647 | PList := libssh2_userauth_list(FAddr, M.AsAnsi(UserName, FCodePage).ToPointer, Length(UserName)); 648 | if Assigned(PList) then 649 | begin 650 | List := AnsiToUnicode(PList, FCodePage); 651 | if Pos('password', List) > 0 then Include(FAuthMethods, amPassword); 652 | if Pos('publickey', List) > 0 then Include(FAuthMethods, amKey); 653 | if Pos('keyboard-interactive', List) > 0 then Include(FAuthMethods, amInteractive); 654 | if Pos('hostbased', List) > 0 then Include(FAuthMethods, amHostBased); 655 | end 656 | else if libssh2_userauth_authenticated(FAddr) <> 0 then 657 | // Unlikely but SSH_USERAUTH_NONE succeded! 658 | FState := session_Connected; 659 | Result := FAuthMethods; 660 | FAuthMethodsCached := True; 661 | end; 662 | 663 | procedure KbdInteractiveCallback(const Name: PAnsiChar; name_len: Integer; 664 | const instruction: PAnsiChar; instruction_len: Integer; num_prompts: Integer; 665 | const prompts: PLIBSSH2_USERAUTH_KBDINT_PROMPT; 666 | responses: PLIBSSH2_USERAUTH_KBDINT_RESPONSE; 667 | _abstract: PPointer); cdecl; 668 | var 669 | Session: TSshSession; 670 | SName, SInstruction, SPrompt : RawByteString; 671 | PromptNo: Integer; 672 | Echo: Boolean; 673 | P: Pointer; 674 | Response: string; 675 | M: TMarshaller; 676 | begin 677 | if _abstract = nil then Exit; 678 | Session := TSshSession(_abstract^); 679 | if not Session.HasKeybIntEvent then Exit; 680 | 681 | SetString(SName, Name, name_len); 682 | SetCodePage(SName, Session.FCodePage, False); 683 | SetString(SInstruction, Instruction, instruction_len); 684 | SetCodePage(SInstruction, Session.FCodePage, False); 685 | {$POINTERMATH ON} 686 | for PromptNo := 0 to num_prompts - 1 do 687 | begin 688 | Echo := prompts[PromptNo].Echo <> 0; 689 | SetString(SPrompt, prompts[PromptNo].text, prompts[PromptNo].length); 690 | Response :=Session.doKeybInt( 691 | string(SName), string(SInstruction), string(SPrompt), Echo); 692 | if Response <> '' then 693 | begin 694 | // libssh2 will be freeing the allocated memory!! 695 | P := AllocMem(Length(Response)+1); 696 | System.AnsiStrings.StrCopy(PAnsiChar(P), 697 | PAnsiChar(M.AsAnsi(Response, Session.FCodePage).ToPointer)); 698 | responses[PromptNo].text := P; 699 | responses[PromptNo].length := Length(Response); 700 | end; 701 | end; 702 | {$POINTERMATH OFF} 703 | end; 704 | 705 | function TSshSession.UserAuth(const UserName: string): Boolean; 706 | begin 707 | if FState = session_Authorized then Exit(True); 708 | if FState <> session_Connected then Exit(False); 709 | 710 | // Also sets FAuthMethods 711 | if UserAuthNone(UserName) then Exit(True); 712 | if (amKey in FAuthMethods) and UserAuthAgent(UserName) then Exit(True); 713 | // UserAuthInteractive also tries password authorization 714 | if (FAuthMethods * [amInteractive, amPassword] <> []) 715 | and UserAuthInteractive(UserName) 716 | then 717 | Exit(True) 718 | else 719 | Exit(False); 720 | end; 721 | 722 | function TSshSession.UserAuthNone(const UserName: string): Boolean; 723 | begin 724 | if FState = session_Authorized then Exit(True); 725 | if FState <> session_Connected then Exit(False); 726 | 727 | FAuthMethods := AuthMethods(UserName); 728 | Result := FState = session_Authorized; 729 | if Result then 730 | FUserName := UserName; 731 | end; 732 | 733 | function TSshSession.UserAuthAgent(const UserName: string): Boolean; 734 | { 735 | Note that only pagent from Putty is supported on Windows 736 | https://github.com/libgit2/libgit2/issues/4958 737 | } 738 | var 739 | Agent: PLIBSSH2_AGENT; 740 | Identity, PrevIdentity: PLIBSSH2_AGENT_PUBLICKEY; 741 | ReturnCode: integer; 742 | M: TMarshaller; 743 | begin 744 | if FState = session_Authorized then Exit(True); 745 | if (FState <> session_Connected) or not (amKey in AuthMethods(UserName)) then Exit(False); 746 | 747 | Result := False; 748 | Agent := libssh2_agent_init(FAddr); 749 | if not Assigned(Agent) then Exit(False); 750 | 751 | ReturnCode := libssh2_agent_connect(Agent); 752 | if ReturnCode = 0 then 753 | begin 754 | try 755 | ReturnCode := libssh2_agent_list_identities(Agent); 756 | if ReturnCode = 0 then 757 | begin 758 | PrevIdentity := nil; 759 | while True do 760 | begin 761 | ReturnCode := libssh2_agent_get_identity(Agent, Identity, PrevIdentity); 762 | if ReturnCode <> 0 then 763 | break; 764 | ReturnCode := libssh2_agent_userauth(Agent, M.AsAnsi(UserName, FCodePage).ToPointer, Identity); 765 | if ReturnCode = 0 then 766 | begin 767 | Result := True; 768 | break; 769 | end; 770 | PrevIdentity := Identity; 771 | end; 772 | end; 773 | finally 774 | libssh2_agent_disconnect(Agent); 775 | libssh2_agent_free(Agent); 776 | end; 777 | end; 778 | 779 | if Result then 780 | begin 781 | FState := session_Authorized; 782 | FUserName := UserName; 783 | end; 784 | end; 785 | 786 | function TSshSession.UserAuthBanner: string; 787 | var 788 | Banner: PAnsiChar; 789 | TmpS: RawByteString; 790 | begin 791 | try 792 | CheckLibSsh2Result(libssh2_userauth_banner(FAddr, Banner), Self, 793 | 'libssh2_userauth_banner'); 794 | except 795 | Exit(''); 796 | end; 797 | 798 | TmpS := Banner; 799 | System.SetCodePage(TmpS, FCodePage, False); 800 | Result := string(TmpS); 801 | end; 802 | 803 | function TSshSession.UserAuthInteractive(const UserName: string): Boolean; 804 | { 805 | For some reason libssh2_userauth_keyboard_interactive does not work 806 | with Windows Hosts. Do a libssh2_userauth_password instead if possible. 807 | } 808 | var 809 | UName: TMarshaller; 810 | Methods: TAuthMethods; 811 | begin 812 | if FState = session_Authorized then Exit(True); 813 | if (FState <> session_Connected) or not HasKeybIntEvent then 814 | Exit(False); 815 | 816 | Methods := AuthMethods(UserName); 817 | if (amInteractive in Methods) and not GetWindowsHost then 818 | Result := 819 | libssh2_userauth_keyboard_interactive(FAddr, 820 | UName.AsAnsi(UserName, FCodePage).ToPointer, 821 | KbdInteractiveCallback) = 0 822 | else if amPassword in Methods then 823 | Result := UserAuthPass(UserName, doKeybInt('', '', Msg_Password, False)) 824 | else 825 | Result := False; 826 | if Result then 827 | begin 828 | FState := session_Authorized; 829 | FUserName := UserName; 830 | end; 831 | end; 832 | 833 | function TSshSession.UserAuthKey(const UserName, PublicKeyFile, PrivateKeyFile, 834 | PassPhrase: string): Boolean; 835 | var 836 | M: TMarshaller; 837 | ReturnValue: Integer; 838 | begin 839 | if FState = session_Authorized then Exit(True); 840 | if FState <> session_Connected then Exit(False); 841 | 842 | if amKey in AuthMethods(UserName) then 843 | begin 844 | repeat 845 | ReturnValue := libssh2_userauth_publickey_fromfile(FAddr, 846 | M.AsAnsi(UserName, FCodePage).ToPointer, 847 | M.AsAnsi(PublicKeyFile, FCodePage).ToPointer, 848 | M.AsAnsi(PrivateKeyFile, FCodePage).ToPointer, 849 | M.AsAnsi(PassPhrase, FCodePage).ToPointer) 850 | until ReturnValue <> LIBSSH2_ERROR_EAGAIN; 851 | //CheckLibSsh2Result(ReturnValue, Self, 'libssh2_userauth_publickey_fromfile'); 852 | Result := ReturnValue = 0; 853 | end 854 | else 855 | Result := False; 856 | 857 | if Result then 858 | begin 859 | FState := session_Authorized; 860 | FUserName := UserName; 861 | end; 862 | end; 863 | 864 | function TSshSession.UserAuthKey(const UserName, PublicKeyFile, 865 | PrivateKeyFile: string): Boolean; 866 | begin 867 | if FState = session_Authorized then Exit(True); 868 | if not HasKeybIntEvent or not (amKey in AuthMethods(UserName)) then Exit(False); 869 | 870 | Result := UserAuthKey(UserName, PublicKeyFile, PrivateKeyFile, 871 | doKeybInt('', Format(Msg_PrivateKeyInstruction, [PrivateKeyFile]), 872 | Msg_PassPhrase, False)); 873 | end; 874 | 875 | function TSshSession.UserAuthPass(const UserName, Password: string): Boolean; 876 | Var 877 | M: TMarshaller; 878 | begin 879 | if FState = session_Authorized then Exit(True); 880 | if FState <> session_Connected then Exit(False); 881 | 882 | Result := 883 | (amPassword in AuthMethods(UserName)) and 884 | (libssh2_userauth_password(FAddr, 885 | M.AsAnsi(UserName, FCodePage).ToPointer, 886 | M.AsAnsi(PassWord, FCodePage).ToPointer) = 0); 887 | if Result then 888 | begin 889 | FState := session_Authorized; 890 | FUserName := UserName; 891 | end; 892 | end; 893 | 894 | procedure TSshSession.SetTimeout(aTimeoutInMs: LongInt); 895 | begin 896 | libssh2_session_set_timeout(Faddr, aTimeoutInMs); 897 | end; 898 | 899 | {$endregion} 900 | 901 | {$region 'TScp'} 902 | type 903 | TScp = class(TInterfacedObject, IScp) 904 | private 905 | FBufferSize: Int64; 906 | FCancelled: Boolean; 907 | FTransferCallback: TTransferProgressCallback; 908 | FSession : ISshSession; 909 | procedure SetBufferSize(Size: Int64); 910 | procedure SetTransferProgressCallback(Callback: TTransferProgressCallback); 911 | procedure Cancel; 912 | procedure Receive(const RemoteFile: string; Stream: TStream); overload; 913 | procedure Receive(const RemoteFile, LocalFile: string); overload; 914 | procedure Send(Stream: TStream; const RemoteFile: string; 915 | Permissions: TFilePermissions = FPDefault; 916 | MTime: TDateTime = 0; ATime: TDateTime = 0); overload; 917 | procedure Send(const LocalFile, RemoteFile: string; 918 | Permissions: TFilePermissions = FPDefault; 919 | MTime: TDateTime = 0; ATime: TDateTime = 0); overload; 920 | public 921 | constructor Create(Session: ISshSession); 922 | end; 923 | 924 | { TScp } 925 | 926 | procedure TScp.Cancel; 927 | begin 928 | FCancelled := True; 929 | end; 930 | 931 | constructor TScp.Create(Session: ISshSession); 932 | begin 933 | inherited Create; 934 | FSession := Session; 935 | FBufferSize := 8 * 1024 - 1; 936 | end; 937 | 938 | procedure TScp.Receive(const RemoteFile, LocalFile: string); 939 | var 940 | FileStream: TFileStream; 941 | begin 942 | FileStream := TFileStream.Create(LocalFile, fmCreate or fmOpenWrite); 943 | try 944 | Receive(RemoteFile, FileStream); 945 | finally 946 | FileStream.Free; 947 | end; 948 | end; 949 | 950 | procedure TScp.Receive(const RemoteFile: string; Stream: TStream); 951 | { Assumes blocking session} 952 | var 953 | Channel: PLIBSSH2_CHANNEL; 954 | Buffer: TBytes; 955 | M : TMarshaller; 956 | Stat: struct_stat; 957 | TotalBytesRead: ssize_t; 958 | BytesRead: ssize_t; 959 | begin 960 | if FSession.SessionState <> session_Authorized then 961 | raise ESshError.CreateRes(@Err_SessionAuth); 962 | 963 | FCancelled := False; 964 | Channel := libssh2_scp_recv2(FSession.Addr, M.AsAnsi(RemoteFile, FSession.CodePage).ToPointer, Stat); 965 | if Channel = nil then 966 | CheckLibSsh2Result(libssh2_session_last_errno(FSession.Addr), FSession, 'libssh2_scp_recv2'); 967 | try 968 | SetLength(Buffer, FBufferSize); 969 | TotalBytesRead := 0; 970 | while TotalBytesRead < Stat.st_size do begin 971 | if FCancelled then Break; 972 | BytesRead := libssh2_channel_read(channel, PAnsiChar(Buffer), FBufferSize); 973 | if BytesRead < 0 then 974 | CheckLibSsh2Result(BytesRead, FSession, 'libssh2_channel_read'); 975 | Inc(TotalBytesRead, BytesRead); 976 | if TotalBytesRead > Stat.St_Size then Dec(BytesRead); // The last byte is #0 977 | Stream.Write(Buffer, BytesRead); 978 | if Assigned(FTransferCallback) then 979 | FTransferCallback(RemoteFile, TotalBytesRead, Stat.st_size); 980 | end; 981 | finally 982 | libssh2_channel_free(Channel); 983 | end; 984 | end; 985 | 986 | procedure TScp.Send(Stream: TStream; const RemoteFile: string; 987 | Permissions: TFilePermissions; MTime: TDateTime; ATime: TDateTime); 988 | var 989 | Channel: PLIBSSH2_CHANNEL; 990 | M: TMarshaller; 991 | Buffer: TBytes; 992 | N, K, R: ssize_t; 993 | Buf: PAnsiChar; 994 | Transfered: UInt64; 995 | begin 996 | if FSession.SessionState <> session_Authorized then 997 | raise ESshError.CreateRes(@Err_SessionAuth); 998 | // 999 | FCancelled := False; 1000 | Channel := libssh2_scp_send64(FSession.Addr, 1001 | M.AsAnsi(RemoteFile, FSession.CodePage).ToPointer, 1002 | Integer(Word(Permissions)), Stream.Size, IfThen(MTime = 0, 0, 1003 | DateTimeToUnix(MTime)), IfThen(ATime = 0, 0, DateTimeToUnix(ATime))); 1004 | if Channel = nil then 1005 | CheckLibSsh2Result(libssh2_session_last_errno(FSession.Addr), FSession, 'libssh2_scp_send64'); 1006 | 1007 | SetLength(Buffer, FBufferSize); 1008 | Transfered := 0; 1009 | try 1010 | repeat 1011 | N := Stream.Read(Buffer, FBufferSize); 1012 | if N > 0 then 1013 | begin 1014 | Buf := PAnsiChar(Buffer); 1015 | K := N; 1016 | repeat 1017 | R := libssh2_channel_write(Channel, Buf, K); 1018 | if R < 0 then 1019 | CheckLibSsh2Result(R, FSession, 'libssh2_channel_write');; 1020 | Inc(Transfered, R); 1021 | Inc(Buf, R); 1022 | Dec(K, R); 1023 | if Assigned(FTransferCallback) then 1024 | FTransferCallback(RemoteFile, Transfered, Stream.Size); 1025 | until (K <= 0) or FCancelled; 1026 | end; 1027 | until (N <= 0) or FCancelled; 1028 | libssh2_channel_send_eof(Channel); 1029 | libssh2_channel_wait_eof(Channel); 1030 | libssh2_channel_wait_closed(Channel); 1031 | finally 1032 | libssh2_channel_free(Channel); 1033 | end; 1034 | end; 1035 | 1036 | procedure TScp.Send(const LocalFile, RemoteFile: string; 1037 | Permissions: TFilePermissions; MTime: TDateTime; ATime: TDateTime); 1038 | var 1039 | FileStream: TFileStream; 1040 | begin 1041 | FileStream := TFileStream.Create(LocalFile, fmOpenRead); 1042 | try 1043 | Send(FileStream, RemoteFile, Permissions, MTime, ATime); 1044 | finally 1045 | FileStream.Free; 1046 | end; 1047 | end; 1048 | 1049 | procedure TScp.SetBufferSize(Size: Int64); 1050 | begin 1051 | FBufferSize := Size; 1052 | end; 1053 | 1054 | procedure TScp.SetTransferProgressCallback(Callback: TTransferProgressCallback); 1055 | begin 1056 | FTransferCallback := Callback; 1057 | end; 1058 | {$endregion} 1059 | 1060 | {$region 'TSshExec'} 1061 | type 1062 | TSshExec = class(TInterfacedObject, ISshExec) 1063 | private 1064 | FSession : ISshSession; 1065 | FBufferSize: Int64; 1066 | FCancelled: Boolean; 1067 | procedure SetBufferSize(Size: Int64); 1068 | procedure Cancel; 1069 | procedure Exec(const Command: string; var Output, ErrOutput: string; var ExitCode: Integer); 1070 | public 1071 | constructor Create(Session: ISshSession); 1072 | end; 1073 | 1074 | { TSshExec } 1075 | 1076 | procedure TSshExec.Cancel; 1077 | begin 1078 | FCancelled := True; 1079 | end; 1080 | 1081 | constructor TSshExec.Create(Session: ISshSession); 1082 | begin 1083 | inherited Create; 1084 | FSession := Session; 1085 | FBufferSize := 8 * 1024 - 1; 1086 | end; 1087 | 1088 | procedure TSshExec.Exec(const Command: string; var Output, ErrOutput: string; 1089 | var ExitCode: Integer); 1090 | var 1091 | Channel: PLIBSSH2_CHANNEL; 1092 | M: TMarshaller; 1093 | ReadBuffer, OutBuffer, ErrBuffer: TBytes; 1094 | StdStream, ErrStream: TBytesStream; 1095 | TimeVal: TTimeVal; 1096 | ReadFds: TFdSet; 1097 | BytesRead: ssize_t; 1098 | ReturnCode: integer; 1099 | OldBlocking: Boolean; 1100 | begin 1101 | if FSession.SessionState <> session_Authorized then 1102 | raise ESshError.CreateRes(@Err_SessionAuth); 1103 | 1104 | FCancelled := False; 1105 | Channel := libssh2_channel_open_session(FSession.Addr); 1106 | if Channel = nil then 1107 | CheckLibSsh2Result(libssh2_session_last_errno(FSession.Addr), FSession, 1108 | 'libssh2_channel_open_session'); 1109 | 1110 | TimeVal.tv_sec := 1; // check for cancel every one second 1111 | TimeVal.tv_usec := 0; 1112 | 1113 | StdStream := TBytesStream.Create(OutBuffer); 1114 | ErrStream := TBytesStream.Create(ErrBuffer); 1115 | SetLength(ReadBuffer, FBufferSize); 1116 | OldBlocking := FSession.Blocking; 1117 | FSession.Blocking := False; 1118 | try 1119 | Repeat 1120 | ReturnCode := libssh2_channel_exec(Channel, 1121 | M.AsAnsi(Command, FSession.CodePage).ToPointer); 1122 | CheckLibSsh2Result(ReturnCode, FSession, 'libssh2_channel_exec'); 1123 | Until ReturnCode <> LIBSSH2_ERROR_EAGAIN; 1124 | 1125 | // Stop waiting if cancelled of Channel is sent EOF 1126 | while not FCancelled do 1127 | begin 1128 | // Wait until there is something to read on the Channel 1129 | Repeat 1130 | FD_ZERO(ReadFds); 1131 | _FD_SET(FSession.Socket, ReadFds); 1132 | ReturnCode := select(0, @ReadFds, nil, nil, @TimeVal); 1133 | if ReturnCode < 0 then CheckSocketResult(WSAGetLastError, 'select'); 1134 | if libssh2_channel_eof(Channel) = 1 then Break; 1135 | Until (ReturnCode > 0) or FCancelled; 1136 | 1137 | try 1138 | // Standard output 1139 | BytesRead := libssh2_channel_read(Channel, PAnsiChar(ReadBuffer), 1140 | FBufferSize); 1141 | CheckLibSsh2Result(BytesRead, FSession, 'libssh2_channel_read_ex'); 1142 | if BytesRead > 0 then 1143 | StdStream.WriteBuffer(ReadBuffer, BytesRead); 1144 | 1145 | // Error output 1146 | BytesRead := libssh2_channel_read_stderr(Channel, 1147 | PAnsiChar(ReadBuffer), FBufferSize); 1148 | CheckLibSsh2Result(BytesRead, FSession, 'libssh2_channel_read_ex'); 1149 | if BytesRead > 0 then 1150 | ErrStream.WriteBuffer(ReadBuffer, BytesRead); 1151 | except 1152 | on E: Exception do 1153 | begin 1154 | OutputDebugString(PChar(E.Message)); 1155 | Break; 1156 | end; 1157 | end; 1158 | 1159 | // BytesRead will be either > 0 or LIBSSH2_ERROR_EAGAIN until 1160 | // the command is processed 1161 | if BytesRead = 0 then Break; 1162 | end; 1163 | 1164 | Output := AnsiToUnicode(PAnsiChar(StdStream.Memory), 1165 | StdStream.Size, FSession.CodePage); 1166 | ErrOutput := AnsiToUnicode(PAnsiChar(ErrStream.Memory), 1167 | ErrStream.Size, FSession.CodePage); 1168 | 1169 | // libssh2_channel_close sends SSH_MSG_CLOSE to the host 1170 | libssh2_channel_close(Channel); 1171 | if FCancelled then 1172 | ExitCode := 130 // ^C on Linux 1173 | else 1174 | Exitcode := libssh2_channel_get_exit_status(Channel); 1175 | finally 1176 | StdStream.Free; 1177 | ErrStream.Free; 1178 | libssh2_channel_free(Channel); 1179 | FSession.Blocking := OldBlocking; 1180 | end; 1181 | end; 1182 | 1183 | procedure TSshExec.SetBufferSize(Size: Int64); 1184 | begin 1185 | FBufferSize := Size; 1186 | end; 1187 | 1188 | {$endregion} 1189 | 1190 | {$region 'Factory Methods'} 1191 | function GetLibSsh2: ILibSsh2; 1192 | begin 1193 | Result := TLibSsh2.Create; 1194 | end; 1195 | 1196 | function CreateSession(Host: string; Port: Word): ISshSession; 1197 | begin 1198 | Result := TSshSession.Create(Host, Port); 1199 | end; 1200 | 1201 | function CreateScp(Session: ISshSession): IScp; 1202 | begin 1203 | Result := TScp.Create(Session); 1204 | end; 1205 | 1206 | 1207 | function CreateSshExec(Session: ISshSession): ISshExec; 1208 | begin 1209 | Result := TSshExec.Create(Session); 1210 | end; 1211 | 1212 | 1213 | {$endregion} 1214 | 1215 | 1216 | end. 1217 | -------------------------------------------------------------------------------- /Source/SshTunnel.pas: -------------------------------------------------------------------------------- 1 | unit SshTunnel; 2 | { 3 | 4 | Copyright (c) 2020 Kiriakos Vlahos (PyScripter) 5 | Delphi wrapper of libssh2 (https://www.libssh2.org/) 6 | 7 | The C header translation and the SFTP implementation draw from 8 | https://bitbucket.org/ZeljkoMarjanovic/libssh2-delphi 9 | Copyright (c) 2010, Zeljko Marjanovic (MPL 1.1) 10 | 11 | Released under the MIT Licence 12 | } 13 | 14 | interface 15 | 16 | Uses 17 | System.SysUtils, 18 | Ssh2Client; 19 | 20 | type 21 | ESshTunnelError = class(Exception); 22 | 23 | ISshTunnel = interface 24 | ['{EB106E13-F168-43A5-BD44-301915814600}'] 25 | procedure SetBufferSize(Size: Int64); 26 | procedure Cancel; 27 | // Forwards a local port to a RemoteHost:RemotePort until Cancelled 28 | procedure ForwardLocalPort(const LocalPort: Word; const RemoteHost: string; 29 | const RemotePort: Word); 30 | property BufferSize: Int64 write SetBufferSize; 31 | end; 32 | 33 | // Factory Method 34 | function CreateSshTunnel(Session: ISshSession): ISshTunnel; 35 | 36 | implementation 37 | 38 | Uses 39 | WinApi.Windows, 40 | Winapi.Winsock2, 41 | System.Classes, 42 | System.SyncObjs, 43 | libssh2, 44 | SocketUtils; 45 | 46 | resourcestring 47 | Err_SessionNotAuth = 'The session is not connected and authorised'; 48 | Err_ConnClosed = 'The connection has been closed'; 49 | 50 | {$region 'TSshTunnel'} 51 | type 52 | TSshTunnel = class(TInterfacedObject, ISshTunnel) 53 | private 54 | FSession: ISshSession; 55 | FCancelled: Boolean; 56 | FBufferSize: Int64; 57 | FSessionLock: TRTLCriticalSection; 58 | procedure SetBufferSize(Size: Int64); 59 | procedure Cancel; 60 | procedure ServeTunnelConnection(const LocalPort: Word; const RemoteHost: 61 | string; const RemotePort: Word; ForwardSock: TSocket; TimeVal: TTimeVal); 62 | procedure ForwardLocalPort(const LocalPort: Word; const RemoteHost: string; 63 | const RemotePort: Word); 64 | public 65 | constructor Create(Session: ISshSession); 66 | destructor Destroy; override; 67 | end; 68 | { TSshTunnel } 69 | 70 | procedure TSshTunnel.Cancel; 71 | begin 72 | FCancelled := True; 73 | end; 74 | 75 | constructor TSshTunnel.Create(Session: ISshSession); 76 | begin 77 | inherited Create; 78 | if Session.SessionState <> session_Authorized then 79 | raise ESshTunnelError.CreateRes(@Err_SessionNotAuth); 80 | FSession := Session; 81 | FBufferSize := 32 * 1024 - 1; 82 | FSessionLock.Initialize; 83 | end; 84 | 85 | destructor TSshTunnel.Destroy; 86 | begin 87 | FSessionLock.Free; 88 | inherited; 89 | end; 90 | 91 | procedure TSshTunnel.ForwardLocalPort(const LocalPort: Word; 92 | const RemoteHost: string; const RemotePort: Word); 93 | { 94 | Note that currently the procedure handles only the first connection that come in 95 | } 96 | const 97 | CheckInterval = 1; // secconds 98 | var 99 | ListenSock: TSocket; 100 | ForwardSock: TSocket; 101 | SocketOption : Integer; 102 | ReadFds: TFdSet; 103 | TimeVal: TTimeVal; 104 | ReturnCode: integer; 105 | ThreadId: Integer; 106 | begin 107 | FCancelled := False; 108 | TimeVal.tv_sec := CheckInterval; // check for cancel every one second 109 | TimeVal.tv_usec := 0; 110 | SocketOption := 1; // Initialize SocketOption 111 | ThreadId := 0; 112 | 113 | ListenSock := GetWinSock.CreateSocketAndListen('localhost', LocalPort); 114 | setsockopt(ListenSock, SOL_SOCKET, SO_REUSEADDR, @SocketOption, sizeof(SocketOption)); 115 | 116 | try 117 | // Wait for TCP connection on LocalPort 118 | repeat 119 | repeat 120 | FD_ZERO(ReadFds); 121 | _FD_SET(ListenSock, ReadFds); 122 | ReturnCode := select(0, @ReadFds, nil, nil, @TimeVal); 123 | if ReturnCode < 0 then CheckSocketResult(WSAGetLastError, 'select'); 124 | until (ReturnCode > 0) or FCancelled; 125 | if FCancelled then Exit; 126 | 127 | ForwardSock := accept(listensock, nil, nil); 128 | if ForwardSock = INVALID_SOCKET then 129 | begin 130 | try 131 | CheckSocketResult(WSAGetLastError, 'accept'); 132 | except on E: Exception do 133 | OutputDebugString(PChar(E.Message)); 134 | end; 135 | Continue; 136 | end; 137 | 138 | TThread.CreateAnonymousThread(procedure 139 | begin 140 | try 141 | Inc(ThreadId); 142 | TThread.NameThreadForDebugging('Connection ' + ThreadId.ToString); 143 | ServeTunnelConnection(LocalPort, RemoteHost, RemotePort, 144 | ForwardSock, TimeVal); 145 | except on E: Exception do 146 | OutputDebugString(PChar(E.Message)); 147 | end 148 | end).Start; 149 | TThread.Yield; 150 | until FCancelled; 151 | 152 | // Wait for the threads to finish 153 | TThread.Yield; 154 | finally 155 | if ListenSock <> INVALID_SOCKET then closesocket(ListenSock); 156 | end; 157 | end; 158 | 159 | procedure TSshTunnel.ServeTunnelConnection(const LocalPort: Word; 160 | const RemoteHost: string; const RemotePort: Word; 161 | ForwardSock: TSocket; TimeVal: TTimeVal); 162 | var 163 | Channel: PLIBSSH2_CHANNEL; 164 | ChannelSock: TSocket; 165 | Buf: TBytes; 166 | Read: Integer; 167 | Total : Integer; 168 | Written: Integer; 169 | ReadFds: TFdSet; 170 | ReturnCode: Integer; 171 | M: TMarshaller; 172 | begin 173 | ChannelSock := FSession.Socket; 174 | Channel := nil; 175 | 176 | try 177 | FSessionLock.Enter; 178 | try 179 | FSession.Blocking := True; 180 | Channel := libssh2_channel_direct_tcpip_ex(FSession.Addr, 181 | M.AsAnsi(RemoteHost, FSession.CodePage).ToPointer, 182 | RemotePort, '127.0.0.1', LocalPort); 183 | if Channel = nil then 184 | CheckLibSsh2Result(libssh2_session_last_errno(FSession.Addr), 185 | FSession, 'libssh2_channel_direct_tcpip_ex'); 186 | finally 187 | // Must use non-blocking IO hereafter due to the current libssh2 API 188 | FSession.Blocking := False; 189 | FSessionLock.Leave; 190 | end; 191 | 192 | // Now transfer data 193 | // ForwardSocket -> Channel 194 | // Channel -> ForwardSocket 195 | SetLength(Buf, FBufferSize); 196 | while not FCancelled do 197 | begin 198 | FD_ZERO(ReadFds); 199 | _FD_SET(ForwardSock, ReadFds); 200 | _FD_SET(ChannelSock, ReadFds); 201 | // wait for action 202 | ReturnCode := select(0, @ReadFds, nil, nil, @TimeVal); 203 | if ReturnCode < 0 then CheckSocketResult(ReturnCode, 'select'); 204 | if ReturnCode = 0 then Continue; 205 | if FCancelled then Exit; 206 | 207 | // we should be able to read now 208 | if FD_ISSET(ForwardSock, ReadFds) then begin 209 | Read := recv(Forwardsock, Buf[0], FBufferSize, 0); 210 | if Read = SOCKET_ERROR then 211 | CheckSocketResult(WSAGetLastError, 'recv'); 212 | if Read = 0 then 213 | Exit; // Connection closed 214 | 215 | FSessionLock.Enter; 216 | try 217 | Total := 0; 218 | while (Total < Read) do 219 | begin 220 | Written := libssh2_channel_write(Channel, PAnsiChar(Buf) + Total, Read - Total); 221 | // Handle EAGAIN 222 | if Written = LIBSSH2_ERROR_EAGAIN then 223 | Continue; 224 | CheckLibSsh2Result(Written, FSession, 'libssh2_channel_write'); 225 | Inc(Total, Written); 226 | end; 227 | finally 228 | FSessionLock.Leave; 229 | end; 230 | end; 231 | if FD_ISSET(ChannelSock, ReadFds) then begin 232 | FSessionLock.Enter; 233 | try 234 | Read := libssh2_channel_read(channel, PAnsiChar(Buf), FBufferSize); 235 | if (Read = 0) or (Read = LIBSSH2_ERROR_EAGAIN) then 236 | // Handle EAGAIN: Go to Wait state 237 | Continue; 238 | CheckLibSsh2Result(Read, FSession, 'libssh2_channel_read'); 239 | finally 240 | FSessionLock.Leave; 241 | end; 242 | 243 | Total := 0; 244 | while (Total < Read) do 245 | begin 246 | Written := send(forwardsock, Buf[Total], Read - Total, 0); 247 | if Written = SOCKET_ERROR then 248 | CheckSocketResult(WSAGetLastError, 'send'); 249 | Inc(Total, Written); 250 | end; 251 | end; 252 | end; 253 | finally 254 | if Channel <> nil then libssh2_channel_free(Channel); 255 | if ForwardSock <> INVALID_SOCKET then closesocket(ForwardSock); 256 | end; 257 | end; 258 | 259 | procedure TSshTunnel.SetBufferSize(Size: Int64); 260 | begin 261 | FBufferSize := Size; 262 | end; 263 | {$endregion} 264 | 265 | 266 | {$region 'Factory Methods'} 267 | function CreateSshTunnel(Session: ISshSession): ISshTunnel; 268 | begin 269 | Result := TSshTunnel.Create(Session); 270 | end; 271 | {$endregion} 272 | 273 | 274 | end. 275 | -------------------------------------------------------------------------------- /Source/libssh2_publickey.pas: -------------------------------------------------------------------------------- 1 | { ** 2 | * Delphi/Pascal Wrapper around the library "libssh2" 3 | * Base repository: 4 | * https://bitbucket.org/ZeljkoMarjanovic/libssh2-delphi 5 | * Contributors: 6 | * https://bitbucket.org/jeroenp/libssh2-delphi 7 | * https://bitbucket.org/VadimLV/libssh2_delphi 8 | * https://github.com/pult/libssh2_delphi/ 9 | * } 10 | unit libssh2_publickey; 11 | 12 | // **zm ** translated to pascal 13 | 14 | interface 15 | 16 | uses 17 | WinApi.Windows, 18 | libssh2; 19 | 20 | {+// Copyright (c) 2004-2006, Sara Golemon } 21 | {-* All rights reserved. } 22 | {-* } 23 | {-* Redistribution and use in source and binary forms, } 24 | {-* with or without modification, are permitted provided } 25 | {-* that the following conditions are met: } 26 | {-* } 27 | {-* Redistributions of source code must retain the above } 28 | {-* copyright notice, this list of conditions and the } 29 | {-* following disclaimer. } 30 | {-* } 31 | {-* Redistributions in binary form must reproduce the above } 32 | {-* copyright notice, this list of conditions and the following } 33 | {-* disclaimer in the documentation and/or other materials } 34 | {-* provided with the distribution. } 35 | {-* } 36 | {-* Neither the name of the copyright holder nor the names } 37 | {-* of any other contributors may be used to endorse or } 38 | {-* promote products derived from this software without } 39 | {-* specific prior written permission. } 40 | {-* } 41 | {-* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND } 42 | {-* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, } 43 | {-* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES } 44 | {-* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE } 45 | {-* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR } 46 | {-* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, } 47 | {-* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, } 48 | {-* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR } 49 | {-* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS } 50 | {-* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, } 51 | {-* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING } 52 | {-* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE } 53 | {-* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY } 54 | {-* OF SUCH DAMAGE. } 55 | {= } 56 | 57 | {+// Note: This include file is only needed for using the } 58 | {-* publickey SUBSYSTEM which is not the same as publickey } 59 | {-* authentication. For authentication you only need libssh2.h } 60 | {-* } 61 | {-* For more information on the publickey subsystem, } 62 | {-* refer to IETF draft: secsh-publickey } 63 | {= } 64 | 65 | type 66 | _LIBSSH2_PUBLICKEY = record end; 67 | TLIBSSH2_PUBLICKEY = _LIBSSH2_PUBLICKEY; 68 | PLIBSSH2_PUBLICKEY = ^TLIBSSH2_PUBLICKEY; 69 | 70 | PLIBSSH2_PUBLICKEY_ATTRIBUTE = ^libssh2_publickey_attribute; 71 | libssh2_publickey_attribute = record 72 | name: PAnsiChar; 73 | name_len: ULong; 74 | value: PAnsiChar; 75 | value_len: ULong; 76 | mandatory: AnsiChar; 77 | end {libssh2_publickey_attribute}; 78 | 79 | _libssh2_publickey_list = record 80 | packet: PByte; {= For freeing } 81 | name: PUCHAR; 82 | name_len: LongInt; 83 | blob: PUCHAR; 84 | blob_len: ULong; 85 | num_attrs: ULong; 86 | attrs: PLIBSSH2_PUBLICKEY_ATTRIBUTE; 87 | {= free me } 88 | end {_libssh2_publickey_list}; 89 | libssh2_publickey_list = _libssh2_publickey_list; 90 | Plibssh2_publickey_list = ^libssh2_publickey_list; 91 | 92 | {+// Publickey Subsystem*/ } 93 | 94 | function libssh2_publickey_init(session: PLIBSSH2_SESSION): PLIBSSH2_PUBLICKEY cdecl; 95 | 96 | type 97 | LIBSSH2_PUBLICKEY_ATTRIBUTE_ARRAY = array of LIBSSH2_PUBLICKEY_ATTRIBUTE; 98 | 99 | function libssh2_publickey_add_ex(pkey: PLIBSSH2_PUBLICKEY; 100 | const name: PByte; 101 | name_len: ULong; 102 | const blob: PByte; 103 | blob_len: ULong; 104 | overwrite: AnsiChar; 105 | num_attrs: ULong; 106 | const attrs: LIBSSH2_PUBLICKEY_ATTRIBUTE_ARRAY): Integer; cdecl; 107 | 108 | function libssh2_publickey_add(pkey: PLIBSSH2_PUBLICKEY; 109 | const name: PByte; 110 | const blob: PByte; 111 | blob_len: ULong; 112 | overwrite: AnsiChar; 113 | num_attrs: ULong; 114 | const attrs: LIBSSH2_PUBLICKEY_ATTRIBUTE_ARRAY): Integer; inline; 115 | 116 | function libssh2_publickey_remove_ex(pkey: PLIBSSH2_PUBLICKEY; 117 | const name: PByte; 118 | name_len: ULong; 119 | const blob: PByte; 120 | blob_len: ULong): Integer; cdecl; 121 | 122 | function libssh2_publickey_remove(pkey: PLIBSSH2_PUBLICKEY; 123 | const name: PByte; 124 | const blob: PByte; 125 | blob_len: ULong): Integer; inline; 126 | 127 | function libssh2_publickey_list_fetch(pkey: PLIBSSH2_PUBLICKEY; 128 | var num_keys: LongInt; 129 | var pkey_list: PLIBSSH2_PUBLICKEY_LIST): Integer; cdecl; 130 | 131 | procedure libssh2_publickey_list_free(pkey: PLIBSSH2_PUBLICKEY; 132 | var pkey_list: LIBSSH2_PUBLICKEY_LIST) cdecl; 133 | 134 | function libssh2_publickey_shutdown(pkey: PLIBSSH2_PUBLICKEY): Integer; cdecl; 135 | 136 | implementation 137 | 138 | function libssh2_publickey_init; external libssh2_name delayed; 139 | function libssh2_publickey_add_ex; external libssh2_name delayed; 140 | function libssh2_publickey_remove_ex; external libssh2_name delayed; 141 | function libssh2_publickey_list_fetch; external libssh2_name delayed; 142 | procedure libssh2_publickey_list_free; external libssh2_name delayed; 143 | function libssh2_publickey_shutdown; external libssh2_name delayed; 144 | 145 | function libssh2_publickey_add(pkey: PLIBSSH2_PUBLICKEY; const name: PByte; const blob: PByte; 146 | blob_len: ULong; overwrite: AnsiChar; num_attrs: ULong; const attrs: LIBSSH2_PUBLICKEY_ATTRIBUTE_ARRAY): Integer; 147 | begin 148 | Result := libssh2_publickey_add_ex(pkey, name, Length(PAnsiChar(name)), blob, blob_len, overwrite, num_attrs, attrs); 149 | end; 150 | 151 | function libssh2_publickey_remove(pkey: PLIBSSH2_PUBLICKEY; const name: PByte; const blob: PByte; blob_len: ULong): Integer; 152 | begin 153 | Result := libssh2_publickey_remove_ex(pkey, name, Length(PAnsiChar(name)), blob, blob_len); 154 | end; 155 | 156 | end. 157 | -------------------------------------------------------------------------------- /Source/libssh2_sftp.pas: -------------------------------------------------------------------------------- 1 | { ** 2 | * Delphi/Pascal Wrapper around the library "libssh2" 3 | * Base repository: 4 | * https://bitbucket.org/ZeljkoMarjanovic/libssh2-delphi 5 | * Contributors: 6 | * https://bitbucket.org/jeroenp/libssh2-delphi 7 | * https://bitbucket.org/VadimLV/libssh2_delphi 8 | * https://github.com/pult/libssh2_delphi/ 9 | * } 10 | unit libssh2_sftp; 11 | 12 | // **zm ** translated to pascal 13 | 14 | interface 15 | 16 | uses 17 | WinApi.Windows, 18 | libssh2; 19 | 20 | {+// Copyright (c) 2004-2008, Sara Golemon } 21 | {-* All rights reserved. } 22 | {-* } 23 | {-* Redistribution and use in source and binary forms, } 24 | {-* with or without modification, are permitted provided } 25 | {-* that the following conditions are met: } 26 | {-* } 27 | {-* Redistributions of source code must retain the above } 28 | {-* copyright notice, this list of conditions and the } 29 | {-* following disclaimer. } 30 | {-* } 31 | {-* Redistributions in binary form must reproduce the above } 32 | {-* copyright notice, this list of conditions and the following } 33 | {-* disclaimer in the documentation and/or other materials } 34 | {-* provided with the distribution. } 35 | {-* } 36 | {-* Neither the name of the copyright holder nor the names } 37 | {-* of any other contributors may be used to endorse or } 38 | {-* promote products derived from this software without } 39 | {-* specific prior written permission. } 40 | {-* } 41 | {-* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND } 42 | {-* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, } 43 | {-* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES } 44 | {-* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE } 45 | {-* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR } 46 | {-* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, } 47 | {-* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, } 48 | {-* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR } 49 | {-* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS } 50 | {-* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, } 51 | {-* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING } 52 | {-* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE } 53 | {-* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY } 54 | {-* OF SUCH DAMAGE. } 55 | {= } 56 | 57 | {+// Note: Version 6 was documented at the time of writing } 58 | {-* However it was marked as "DO NOT IMPLEMENT" due to pending changes } 59 | {-* } 60 | {-* Let's start with Version 3 (The version found in OpenSSH) and go from there } 61 | {= } 62 | const 63 | LIBSSH2_SFTP_VERSION = 3; 64 | 65 | LIBSSH2_SFTP_PACKET_MAXLEN = 40000; 66 | 67 | type 68 | _LIBSSH2_SFTP = record end; 69 | LIBSSH2_SFTP_HANDLE = record end; 70 | _LIBSSH2_SFTP_HANDLE = LIBSSH2_SFTP_HANDLE; 71 | PLIBSSH2_SFTP = ^_LIBSSH2_SFTP; 72 | PLIBSSH2_SFTP_HANDLE = ^LIBSSH2_SFTP_HANDLE; 73 | 74 | const 75 | LIBSSH2_SFTP_OPENFILE = 0; 76 | LIBSSH2_SFTP_OPENDIR_ = 1; 77 | {+// Flags for rename_ex()*/ } 78 | LIBSSH2_SFTP_RENAME_OVERWRITE = $00000001; 79 | LIBSSH2_SFTP_RENAME_ATOMIC = $00000002; 80 | LIBSSH2_SFTP_RENAME_NATIVE = $00000004; 81 | {+// Flags for stat_ex()*/ } 82 | LIBSSH2_SFTP_STAT_ = 0; 83 | LIBSSH2_SFTP_LSTAT_ = 1; 84 | LIBSSH2_SFTP_SETSTAT_ = 2; 85 | {+// Flags for symlink_ex()*/ } 86 | LIBSSH2_SFTP_SYMLINK_ = 0; 87 | LIBSSH2_SFTP_READLINK_ = 1; 88 | LIBSSH2_SFTP_REALPATH_ = 2; 89 | {+// SFTP attribute flag bits*/ } 90 | LIBSSH2_SFTP_ATTR_SIZE = $00000001; 91 | LIBSSH2_SFTP_ATTR_UIDGID = $00000002; 92 | LIBSSH2_SFTP_ATTR_PERMISSIONS = $00000004; 93 | LIBSSH2_SFTP_ATTR_ACMODTIME = $00000008; 94 | LIBSSH2_SFTP_ATTR_EXTENDED = $80000000; 95 | 96 | {+// If flags & ATTR_* bit is set, then the value in this struct will be } 97 | {-* meaningful Otherwise it should be ignored } 98 | {= } 99 | type 100 | _LIBSSH2_SFTP_ATTRIBUTES = record 101 | flags: LongWord; 102 | filesize: LIBSSH2_UINT64_T; 103 | uid, gid: LongWord; 104 | permissions: LongWord; 105 | atime, mtime: LongWord; 106 | end; 107 | 108 | LIBSSH2_SFTP_ATTRIBUTES = _LIBSSH2_SFTP_ATTRIBUTES; 109 | PLIBSSH2_SFTP_ATTRIBUTES = ^_LIBSSH2_SFTP_ATTRIBUTES; 110 | 111 | _LIBSSH2_SFTP_STATVFS = record 112 | f_bsize, {/* file system block size */} 113 | f_frsize, {/* fragment size */} 114 | f_blocks, {/* size of fs in f_frsize units */} 115 | f_bfree, {/* # free blocks */} 116 | f_bavail, {/* # free blocks for non-root */} 117 | f_files, {/* # inodes */} 118 | f_ffree, {/* # free inodes */} 119 | f_favail, {/* # free inodes for non-root */} 120 | f_fsid, {/* file system ID */} 121 | f_flag, {/* mount flags */} 122 | f_namemax: libssh2_uint64_t; {/* maximum filename length */} 123 | end; 124 | TLIBSSH2_SFTP_STATVFS = _LIBSSH2_SFTP_STATVFS; 125 | PLIBSSH2_SFTP_STATVFS = ^TLIBSSH2_SFTP_STATVFS; 126 | 127 | const 128 | {+// SFTP filetypes*/ } 129 | LIBSSH2_SFTP_TYPE_REGULAR = 1; 130 | LIBSSH2_SFTP_TYPE_DIRECTORY = 2; 131 | LIBSSH2_SFTP_TYPE_SYMLINK = 3; 132 | LIBSSH2_SFTP_TYPE_SPECIAL = 4; 133 | LIBSSH2_SFTP_TYPE_UNKNOWN = 5; 134 | LIBSSH2_SFTP_TYPE_SOCKET = 6; 135 | LIBSSH2_SFTP_TYPE_CHAR_DEVICE = 7; 136 | LIBSSH2_SFTP_TYPE_BLOCK_DEVICE = 8; 137 | LIBSSH2_SFTP_TYPE_FIFO = 9; 138 | 139 | {+// } 140 | {-* Reproduce the POSIX file modes here for systems that are not POSIX } 141 | {-* compliant. } 142 | {-* } 143 | {-* These is used in "permissions" of "struct _LIBSSH2_SFTP_ATTRIBUTES" } 144 | {= } 145 | {+// File type*/ } 146 | 147 | LIBSSH2_SFTP_S_IFMT = 61440; {/* type of file mask*/} 148 | LIBSSH2_SFTP_S_IFIFO = 4096; {/* named pipe (fifo)*/} 149 | LIBSSH2_SFTP_S_IFCHR = 8192; {/* character special*/} 150 | LIBSSH2_SFTP_S_IFDIR = 16384; {/* directory*/} 151 | LIBSSH2_SFTP_S_IFBLK = 24576; {/* block special*/} 152 | LIBSSH2_SFTP_S_IFREG = 32768; {/* regular*/} 153 | LIBSSH2_SFTP_S_IFLNK = 40960; {/* symbolic link*/} 154 | LIBSSH2_SFTP_S_IFSOCK = 49152; {/* socket*/} 155 | 156 | {+// File mode*/ } 157 | {+// Read, write, execute/search by owner*/ } 158 | LIBSSH2_SFTP_S_IRWXU = 448; {/* RWX mask for owner*/} 159 | LIBSSH2_SFTP_S_IRUSR = 256; {/* R for owner*/} 160 | LIBSSH2_SFTP_S_IWUSR = 128; {/* W for owner*/} 161 | LIBSSH2_SFTP_S_IXUSR = 64; {/* X for owner*/} 162 | {+// Read, write, execute/search by group*/ } 163 | LIBSSH2_SFTP_S_IRWXG = 56; {/* RWX mask for group*/} 164 | LIBSSH2_SFTP_S_IRGRP = 32; {/* R for group*/} 165 | LIBSSH2_SFTP_S_IWGRP = 16; {/* W for group*/} 166 | LIBSSH2_SFTP_S_IXGRP = 8; {/* X for group*/} 167 | {+// Read, write, execute/search by others*/ } 168 | LIBSSH2_SFTP_S_IRWXO = 7; {/* RWX mask for other*/} 169 | LIBSSH2_SFTP_S_IROTH = 4; {/* R for other*/} 170 | LIBSSH2_SFTP_S_IWOTH = 2; {/* W for other*/} 171 | LIBSSH2_SFTP_S_IXOTH = 1; {/* X for other*/} 172 | 173 | // ** zm: setuid/gid i sticky bit nisu definisani u originalnom header-u 174 | LIBSSH2_SFTP_S_ISUID = 2048; // set UID bit 175 | LIBSSH2_SFTP_S_ISGID = 1024; // set-group-ID bit 176 | LIBSSH2_SFTP_S_ISVTX = 512; // sticky bit 177 | 178 | {+// SFTP File Transfer Flags -- (e.g. flags parameter to sftp_open()) } 179 | {=* Danger will robinson... APPEND doesn't have any effect on OpenSSH servers } 180 | LIBSSH2_FXF_READ = $00000001; 181 | LIBSSH2_FXF_WRITE = $00000002; 182 | LIBSSH2_FXF_APPEND = $00000004; 183 | LIBSSH2_FXF_CREAT = $00000008; 184 | LIBSSH2_FXF_TRUNC = $00000010; 185 | LIBSSH2_FXF_EXCL = $00000020; 186 | 187 | {+// SFTP Status Codes (returned by libssh2_sftp_last_error() )*/ } 188 | LIBSSH2_FX_OK = 0; 189 | LIBSSH2_FX_EOF = 1; 190 | LIBSSH2_FX_NO_SUCH_FILE = 2; 191 | LIBSSH2_FX_PERMISSION_DENIED = 3; 192 | LIBSSH2_FX_FAILURE = 4; 193 | LIBSSH2_FX_BAD_MESSAGE = 5; 194 | LIBSSH2_FX_NO_CONNECTION = 6; 195 | LIBSSH2_FX_CONNECTION_LOST = 7; 196 | LIBSSH2_FX_OP_UNSUPPORTED = 8; 197 | LIBSSH2_FX_INVALID_HANDLE = 9; 198 | LIBSSH2_FX_NO_SUCH_PATH = 10; 199 | LIBSSH2_FX_FILE_ALREADY_EXISTS = 11; 200 | LIBSSH2_FX_WRITE_PROTECT = 12; 201 | LIBSSH2_FX_NO_MEDIA = 13; 202 | LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM = 14; 203 | LIBSSH2_FX_QUOTA_EXCEEDED = 15; 204 | // LIBSSH2_FX_UNKNOWN_PRINCIPLE = 16; {/* Initial mis-spelling*/} 205 | LIBSSH2_FX_UNKNOWN_PRINCIPAL = 16; 206 | // LIBSSH2_FX_LOCK_CONFlICT = 17; {/* Initial mis-spelling*/} 207 | LIBSSH2_FX_LOCK_CONFLICT = 17; 208 | LIBSSH2_FX_DIR_NOT_EMPTY = 18; 209 | LIBSSH2_FX_NOT_A_DIRECTORY = 19; 210 | LIBSSH2_FX_INVALID_FILENAME = 20; 211 | LIBSSH2_FX_LINK_LOOP = 21; 212 | 213 | {+// Returned by any function that would block during a read/write opperation*/ } 214 | LIBSSH2SFTP_EAGAIN = LIBSSH2_ERROR_EAGAIN; 215 | {+// SFTP API*/ } 216 | 217 | function libssh2_sftp_init(session: PLIBSSH2_SESSION): PLIBSSH2_SFTP; cdecl; 218 | 219 | function libssh2_sftp_shutdown(sftp: PLIBSSH2_SFTP): Integer; cdecl; 220 | 221 | function libssh2_sftp_last_error(sftp: PLIBSSH2_SFTP): ULong; cdecl; 222 | 223 | function libssh2_sftp_get_channel(sftp: PLIBSSH2_SFTP):PLIBSSH2_CHANNEL; cdecl; 224 | 225 | {+// File / Directory Ops*/ } 226 | 227 | function libssh2_sftp_open_ex(sftp: PLIBSSH2_SFTP; 228 | const filename: PAnsiChar; 229 | filename_len: UInt; 230 | flags: ULong; 231 | mode: LongInt; 232 | open_type: Integer): PLIBSSH2_SFTP_HANDLE; cdecl; 233 | 234 | function libssh2_sftp_open(sftp: PLIBSSH2_SFTP; 235 | const filename: PAnsiChar; 236 | flags: ULong; 237 | mode: LongInt): PLIBSSH2_SFTP_HANDLE; inline; 238 | 239 | function libssh2_sftp_opendir(sftp: PLIBSSH2_SFTP; 240 | const path: PAnsiChar): PLIBSSH2_SFTP_HANDLE; inline; 241 | 242 | function libssh2_sftp_read(handle: PLIBSSH2_SFTP_HANDLE; 243 | buffer: PAnsiChar; 244 | buffer_maxlen: size_t): ssize_t; cdecl; 245 | 246 | function libssh2_sftp_readdir_ex(handle: PLIBSSH2_SFTP_HANDLE; 247 | buffer: PAnsiChar; 248 | buffer_maxlen: size_t; 249 | longentry: PAnsiChar; 250 | longentry_maxlen: size_t; 251 | attrs: PLIBSSH2_SFTP_ATTRIBUTES): Integer; cdecl; 252 | 253 | function libssh2_sftp_readdir(handle: PLIBSSH2_SFTP_HANDLE; 254 | buffer: PAnsiChar; 255 | buffer_maxlen: size_t; attrs: PLIBSSH2_SFTP_ATTRIBUTES): Integer; inline; 256 | 257 | function libssh2_sftp_write(handle: PLIBSSH2_SFTP_HANDLE; 258 | const buffer: PAnsiChar; 259 | count: size_t): ssize_t; cdecl; 260 | 261 | function libssh2_sftp_close_handle(handle: PLIBSSH2_SFTP_HANDLE): Integer; cdecl; 262 | 263 | function libssh2_sftp_close(handle: PLIBSSH2_SFTP_HANDLE): Integer; inline; 264 | 265 | function libssh2_sftp_closedir(handle: PLIBSSH2_SFTP_HANDLE): Integer; inline; 266 | 267 | procedure libssh2_sftp_seek(handle: PLIBSSH2_SFTP_HANDLE; 268 | offset: size_t); cdecl; 269 | 270 | procedure libssh2_sftp_seek64(handle: PLIBSSH2_SFTP_HANDLE; 271 | offset: LIBSSH2_UINT64_T); cdecl; 272 | 273 | procedure libssh2_sftp_rewind(handle: PLIBSSH2_SFTP_HANDLE); inline; 274 | 275 | function libssh2_sftp_tell(handle: PLIBSSH2_SFTP_HANDLE): UInt; cdecl; 276 | 277 | function libssh2_sftp_tell64(handle: PLIBSSH2_SFTP_HANDLE): UInt64; cdecl; 278 | 279 | function libssh2_sftp_fstat_ex(handle: PLIBSSH2_SFTP_HANDLE; 280 | var attrs: LIBSSH2_SFTP_ATTRIBUTES; 281 | setstat: Integer): Integer; cdecl; 282 | 283 | function libssh2_sftp_fstat(handle: PLIBSSH2_SFTP_HANDLE; 284 | var attrs: LIBSSH2_SFTP_ATTRIBUTES): Integer; inline; 285 | 286 | function libssh2_sftp_fsetstat(handle: PLIBSSH2_SFTP_HANDLE; 287 | var attrs: LIBSSH2_SFTP_ATTRIBUTES): Integer; inline; 288 | 289 | {+// Miscellaneous Ops*/ } 290 | 291 | function libssh2_sftp_rename_ex(sftp: PLIBSSH2_SFTP; 292 | const source_filename: PAnsiChar; 293 | srouce_filename_len: UInt; 294 | const dest_filename: PAnsiChar; 295 | dest_filename_len: UInt; 296 | flags: LongInt): Integer; cdecl; 297 | 298 | function libssh2_sftp_rename(sftp: PLIBSSH2_SFTP; 299 | const source_filename: PAnsiChar; 300 | const dest_filename: PAnsiChar): Integer; inline; 301 | 302 | function libssh2_sftp_unlink_ex(sftp: PLIBSSH2_SFTP; 303 | const filename: PAnsiChar; 304 | filename_len: UInt): Integer; cdecl; 305 | 306 | function libssh2_sftp_unlink(sftp: PLIBSSH2_SFTP; 307 | const filename: PAnsiChar): Integer; inline; 308 | 309 | function libssh2_sftp_fstatvfs(handle: PLIBSSH2_SFTP_HANDLE; 310 | var st: TLIBSSH2_SFTP_STATVFS): Integer; cdecl; 311 | 312 | function libssh2_sftp_statvfs(sftp: PLIBSSH2_SFTP; 313 | const path: PAnsiChar; 314 | path_len: size_t; 315 | var st: TLIBSSH2_SFTP_STATVFS): Integer; cdecl; 316 | 317 | function libssh2_sftp_mkdir_ex(sftp: PLIBSSH2_SFTP; 318 | const path: PAnsiChar; 319 | path_len: UInt; 320 | mode: LongInt): Integer; cdecl; 321 | 322 | function libssh2_sftp_mkdir(sftp: PLIBSSH2_SFTP; 323 | const path: PAnsiChar; 324 | mode: LongInt): Integer; inline; 325 | 326 | function libssh2_sftp_rmdir_ex(sftp: PLIBSSH2_SFTP; 327 | const path: PAnsiChar; 328 | path_len: UInt): Integer; cdecl; 329 | 330 | function libssh2_sftp_rmdir(sftp: PLIBSSH2_SFTP; 331 | const path: PAnsiChar): Integer; inline; 332 | 333 | function libssh2_sftp_stat_ex(sftp: PLIBSSH2_SFTP; 334 | const path: PAnsiChar; 335 | path_len: UInt; 336 | stat_type: Integer; 337 | var attrs: LIBSSH2_SFTP_ATTRIBUTES): Integer; cdecl; 338 | 339 | function libssh2_sftp_stat(sftp: PLIBSSH2_SFTP; 340 | const path: PAnsiChar; 341 | var attrs: LIBSSH2_SFTP_ATTRIBUTES): Integer; inline; 342 | 343 | function libssh2_sftp_lstat(sftp: PLIBSSH2_SFTP; 344 | const path: PAnsiChar; 345 | var attrs: LIBSSH2_SFTP_ATTRIBUTES): Integer; inline; 346 | 347 | function libssh2_sftp_setstat(sftp: PLIBSSH2_SFTP; 348 | const path: PAnsiChar; 349 | var attrs: LIBSSH2_SFTP_ATTRIBUTES): Integer; inline; 350 | 351 | function libssh2_sftp_symlink_ex(sftp: PLIBSSH2_SFTP; 352 | const path: PAnsiChar; 353 | path_len: UInt; 354 | target: PAnsiChar; 355 | target_len: UInt; 356 | link_type: Integer): Integer; cdecl; 357 | 358 | function libssh2_sftp_symlink(sftp: PLIBSSH2_SFTP; 359 | const orig: PAnsiChar; 360 | linkpath: PAnsiChar): Integer; inline; 361 | 362 | function libssh2_sftp_readlink(sftp: PLIBSSH2_SFTP; 363 | const path: PAnsiChar; 364 | target: PAnsiChar; 365 | maxlen: UInt): Integer; inline; 366 | 367 | function libssh2_sftp_realpath(sftp: PLIBSSH2_SFTP; 368 | const path: PAnsiChar; 369 | target: PAnsiChar; 370 | maxlen: UInt): Integer; inline; 371 | 372 | implementation 373 | 374 | {$WARN SYMBOL_PLATFORM OFF} // W002 375 | 376 | function libssh2_sftp_init; external libssh2_name delayed; 377 | function libssh2_sftp_shutdown; external libssh2_name delayed; 378 | function libssh2_sftp_last_error; external libssh2_name delayed; 379 | function libssh2_sftp_get_channel; external libssh2_name delayed; 380 | function libssh2_sftp_open_ex; external libssh2_name delayed; 381 | function libssh2_sftp_read; external libssh2_name delayed; 382 | function libssh2_sftp_readdir_ex; external libssh2_name delayed; 383 | function libssh2_sftp_write; external libssh2_name delayed; 384 | function libssh2_sftp_close_handle; external libssh2_name delayed; 385 | procedure libssh2_sftp_seek; external libssh2_name delayed; 386 | procedure libssh2_sftp_seek64; external libssh2_name delayed; 387 | function libssh2_sftp_tell; external libssh2_name delayed; 388 | function libssh2_sftp_tell64; external libssh2_name delayed; 389 | function libssh2_sftp_fstat_ex; external libssh2_name delayed; 390 | function libssh2_sftp_rename_ex; external libssh2_name delayed; 391 | function libssh2_sftp_unlink_ex; external libssh2_name delayed; 392 | function libssh2_sftp_fstatvfs; external libssh2_name delayed; 393 | function libssh2_sftp_statvfs; external libssh2_name delayed; 394 | function libssh2_sftp_mkdir_ex; external libssh2_name delayed; 395 | function libssh2_sftp_rmdir_ex; external libssh2_name delayed; 396 | function libssh2_sftp_stat_ex; external libssh2_name delayed; 397 | function libssh2_sftp_symlink_ex; external libssh2_name delayed; 398 | 399 | function libssh2_sftp_open(sftp: PLIBSSH2_SFTP; const filename: PAnsiChar; flags: ULong; mode: LongInt): PLIBSSH2_SFTP_HANDLE; 400 | begin 401 | Result := libssh2_sftp_open_ex(sftp, filename, Length(filename), flags, mode, LIBSSH2_SFTP_OPENFILE); 402 | end; 403 | 404 | function libssh2_sftp_opendir(sftp: PLIBSSH2_SFTP; const path: PAnsiChar): PLIBSSH2_SFTP_HANDLE; 405 | begin 406 | Result := libssh2_sftp_open_ex(sftp, path, Length(path), 0, 0, LIBSSH2_SFTP_OPENDIR_); 407 | end; 408 | 409 | function libssh2_sftp_readdir(handle: PLIBSSH2_SFTP_HANDLE; buffer: PAnsiChar; buffer_maxlen: size_t; attrs: PLIBSSH2_SFTP_ATTRIBUTES): Integer; 410 | begin 411 | Result := libssh2_sftp_readdir_ex(handle, buffer, buffer_maxlen, nil, 0, attrs); 412 | end; 413 | 414 | function libssh2_sftp_close(handle: PLIBSSH2_SFTP_HANDLE): Integer; 415 | begin 416 | Result := libssh2_sftp_close_handle(handle); 417 | end; 418 | 419 | function libssh2_sftp_closedir(handle: PLIBSSH2_SFTP_HANDLE): Integer; 420 | begin 421 | Result := libssh2_sftp_close_handle(handle); 422 | end; 423 | 424 | procedure libssh2_sftp_rewind(handle: PLIBSSH2_SFTP_HANDLE); 425 | begin 426 | libssh2_sftp_seek64(handle, 0); 427 | end; 428 | 429 | function libssh2_sftp_fstat(handle: PLIBSSH2_SFTP_HANDLE; var attrs: LIBSSH2_SFTP_ATTRIBUTES): Integer; inline; 430 | begin 431 | Result := libssh2_sftp_fstat_ex(handle, attrs, 0); 432 | end; 433 | 434 | function libssh2_sftp_fsetstat(handle: PLIBSSH2_SFTP_HANDLE; var attrs: LIBSSH2_SFTP_ATTRIBUTES): Integer; inline; 435 | begin 436 | Result := libssh2_sftp_fstat_ex(handle, attrs, 1); 437 | end; 438 | 439 | function libssh2_sftp_rename(sftp: PLIBSSH2_SFTP; const source_filename: PAnsiChar; const dest_filename: PAnsiChar): Integer; 440 | begin 441 | Result := libssh2_sftp_rename_ex(sftp, 442 | source_filename, Length(source_filename), 443 | dest_filename, Length(dest_filename), 444 | LIBSSH2_SFTP_RENAME_OVERWRITE or LIBSSH2_SFTP_RENAME_ATOMIC or LIBSSH2_SFTP_RENAME_NATIVE); 445 | end; 446 | 447 | function libssh2_sftp_unlink(sftp: PLIBSSH2_SFTP; const filename: PAnsiChar): Integer; 448 | begin 449 | Result := libssh2_sftp_unlink_ex(sftp, filename, Length(filename)); 450 | end; 451 | 452 | function libssh2_sftp_mkdir(sftp: PLIBSSH2_SFTP; const path: PAnsiChar; mode: LongInt): Integer; 453 | begin 454 | Result := libssh2_sftp_mkdir_ex(sftp, path, Length(path), mode); 455 | end; 456 | 457 | function libssh2_sftp_rmdir(sftp: PLIBSSH2_SFTP; const path: PAnsiChar): Integer; 458 | begin 459 | Result := libssh2_sftp_rmdir_ex(sftp, path, Length(path)); 460 | end; 461 | 462 | function libssh2_sftp_stat(sftp: PLIBSSH2_SFTP; const path: PAnsiChar; var attrs: LIBSSH2_SFTP_ATTRIBUTES): Integer; 463 | begin 464 | Result := libssh2_sftp_stat_ex(sftp, path, Length(path), LIBSSH2_SFTP_STAT_, attrs); 465 | end; 466 | 467 | function libssh2_sftp_lstat(sftp: PLIBSSH2_SFTP; const path: PAnsiChar; var attrs: LIBSSH2_SFTP_ATTRIBUTES): Integer; 468 | begin 469 | Result := libssh2_sftp_stat_ex(sftp, path, Length(path), LIBSSH2_SFTP_LSTAT_, attrs); 470 | end; 471 | 472 | function libssh2_sftp_setstat(sftp: PLIBSSH2_SFTP; const path: PAnsiChar; var attrs: LIBSSH2_SFTP_ATTRIBUTES): Integer; 473 | begin 474 | Result := libssh2_sftp_stat_ex(sftp, path, Length(path), LIBSSH2_SFTP_SETSTAT_, attrs); 475 | end; 476 | 477 | function libssh2_sftp_symlink(sftp: PLIBSSH2_SFTP; const orig: PAnsiChar; linkpath: PAnsiChar): Integer; 478 | begin 479 | Result := libssh2_sftp_symlink_ex(sftp, orig, Length(orig), linkpath, Length(linkpath), LIBSSH2_SFTP_SYMLINK_); 480 | end; 481 | 482 | function libssh2_sftp_readlink(sftp: PLIBSSH2_SFTP; const path: PAnsiChar; target: PAnsiChar; maxlen: UInt): Integer; 483 | begin 484 | Result := libssh2_sftp_symlink_ex(sftp, path, Length(path), target, maxlen, LIBSSH2_SFTP_READLINK_); 485 | end; 486 | 487 | function libssh2_sftp_realpath(sftp: PLIBSSH2_SFTP; const path: PAnsiChar; target: PAnsiChar; maxlen: UInt): Integer; 488 | begin 489 | Result := libssh2_sftp_symlink_ex(sftp, path, Length(path), target, maxlen, LIBSSH2_SFTP_REALPATH_); 490 | end; 491 | 492 | end. 493 | --------------------------------------------------------------------------------