2 ===================================================================
3 --- config.w32 (.../tags/RELEASE_0_11_0)
4 +++ config.w32 (.../trunk)
9 +ARG_WITH("ssh2", "SSH2 support", "no");
11 +if (PHP_SSH2 != "no") {
12 + if ((((PHP_ZLIB=="no") && (CHECK_LIB("zlib_a.lib", "ssh2", PHP_SSH2) || CHECK_LIB("zlib.lib", "ssh2", PHP_SSH2))) ||
13 + (PHP_ZLIB_SHARED && CHECK_LIB("zlib.lib", "ssh2", PHP_SSH2)) || (PHP_ZLIB == "yes" && (!PHP_ZLIB_SHARED))) &&
14 + CHECK_LIB("libeay32.lib", "ssh2", PHP_SSH2) &&
15 + CHECK_LIB("ssleay32.lib", "ssh2", PHP_SSH2) &&
16 + CHECK_LIB("ws2_32.lib", "ssh2", PHP_SSH2)) {
18 + // Use bundled lib if none installed, even if it is outdated.
19 + if (!(CHECK_LIB("libssh2_a.lib;libssh2.lib", "ssh2", PHP_SSH2) &&
20 + CHECK_HEADER_ADD_INCLUDE("libssh2.h", "CFLAGS_SSH2", PHP_PHP_BUILD + "\\include\\libssh2"))) {
21 + FSO.CopyFile(configure_module_dirname + "\\libssh2\\src\\libssh2_config.h.in.w32",
22 + configure_module_dirname + "\\libssh2\\src\\libssh2_config.h");
24 + ADD_FLAG('CFLAGS_SSH2', '/DLIBSSH2_WIN32=1 /DLIBSSH2_API= /I ' +
25 + configure_module_dirname + '/libssh2/include');
28 + AC_DEFINE('HAVE_SSH2LIB', 1);
29 + AC_DEFINE('PHP_SSH2_REMOTE_FORWARDING', 1);
30 + AC_DEFINE('PHP_SSH2_HOSTBASED_AUTH', 1);
31 + AC_DEFINE('PHP_SSH2_POLL', 1);
32 + AC_DEFINE('PHP_SSH2_PUBLICKEY_SUBSYSTEM', 1);
34 + EXTENSION("ssh2", "ssh2.c ssh2_fopen_wrappers.c ssh2_sftp.c");
36 + ADD_SOURCES(configure_module_dirname + "/libssh2/src", "channel.c comp.c crypt.c \
37 + hostkey.c kex.c mac.c misc.c openssl.c packet.c pem.c publickey.c scp.c \
38 + session.c sftp.c transport.c userauth.c", "ssh2");
40 + WARNING("ssh2 not enabled: libraries or headers not found");
44 Property changes on: config.w32
45 ___________________________________________________________________
49 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
50 Added: cvs2svn:cvs-rev
54 ===================================================================
55 --- ssh2.c (.../tags/RELEASE_0_11_0)
56 +++ ssh2.c (.../trunk)
58 int le_ssh2_pkey_subsys;
63 - ZEND_BEGIN_ARG_INFO(php_ssh2_first_arg_force_ref, 0)
64 - ZEND_ARG_PASS_INFO(1)
67 -static unsigned char php_ssh2_first_arg_force_ref[] = { 1, BYREF_FORCE };
69 +ZEND_BEGIN_ARG_INFO(php_ssh2_first_arg_force_ref, 0)
70 + ZEND_ARG_PASS_INFO(1)
76 /* {{{ php_ssh2_set_callback
77 * Try to set a method if it's passed in with the hash table
79 -static int php_ssh2_set_callback(LIBSSH2_SESSION *session, HashTable *ht, char *callback, int callback_len, int callback_type, php_ssh2_session_data *data)
80 +static int php_ssh2_set_callback(LIBSSH2_SESSION *session, HashTable *ht, char *callback, int callback_len, int callback_type, php_ssh2_session_data *data TSRMLS_DC)
82 zval **handler, *copyval;
83 void *internal_handler;
88 - if (!handler || !*handler || !zend_is_callable(*handler, 0, NULL)) {
89 + if (!handler || !*handler || !zend_is_callable(*handler, 0, NULL ZEND_IS_CALLABLE_TSRMLS_CC)) {
95 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to initialize SSH2 session");
98 + closesocket(socket);
101 libssh2_banner_set(session, LIBSSH2_SSH_DEFAULT_BANNER " PHP");
102 @@ -411,19 +406,19 @@
104 /* ignore debug disconnect macerror */
106 - if (php_ssh2_set_callback(session, HASH_OF(callbacks), "ignore", sizeof("ignore") - 1, LIBSSH2_CALLBACK_IGNORE, data)) {
107 + if (php_ssh2_set_callback(session, HASH_OF(callbacks), "ignore", sizeof("ignore") - 1, LIBSSH2_CALLBACK_IGNORE, data TSRMLS_CC)) {
108 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed setting IGNORE callback");
111 - if (php_ssh2_set_callback(session, HASH_OF(callbacks), "debug", sizeof("debug") - 1, LIBSSH2_CALLBACK_DEBUG, data)) {
112 + if (php_ssh2_set_callback(session, HASH_OF(callbacks), "debug", sizeof("debug") - 1, LIBSSH2_CALLBACK_DEBUG, data TSRMLS_CC)) {
113 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed setting DEBUG callback");
116 - if (php_ssh2_set_callback(session, HASH_OF(callbacks), "macerror", sizeof("macerror") - 1, LIBSSH2_CALLBACK_MACERROR, data)) {
117 + if (php_ssh2_set_callback(session, HASH_OF(callbacks), "macerror", sizeof("macerror") - 1, LIBSSH2_CALLBACK_MACERROR, data TSRMLS_CC)) {
118 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed setting MACERROR callback");
121 - if (php_ssh2_set_callback(session, HASH_OF(callbacks), "disconnect", sizeof("disconnect") - 1, LIBSSH2_CALLBACK_DISCONNECT, data)) {
122 + if (php_ssh2_set_callback(session, HASH_OF(callbacks), "disconnect", sizeof("disconnect") - 1, LIBSSH2_CALLBACK_DISCONNECT, data TSRMLS_CC)) {
123 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed setting DISCONNECT callback");
128 last_error = libssh2_session_last_error(session, &error_msg, NULL, 0);
129 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error starting up SSH connection(%d): %s", last_error, error_msg);
131 + closesocket(socket);
132 libssh2_session_free(session);
135 @@ -1148,7 +1143,7 @@
136 zval_ptr_dtor(&(*data)->disconnect_cb);
139 - close((*data)->socket);
140 + closesocket((*data)->socket);
144 @@ -1274,7 +1269,7 @@
146 /* {{{ ssh2_functions[]
148 -function_entry ssh2_functions[] = {
149 +zend_function_entry ssh2_functions[] = {
150 PHP_FE(ssh2_connect, NULL)
151 PHP_FE(ssh2_methods_negotiated, NULL)
152 PHP_FE(ssh2_fingerprint, NULL)
154 Property changes on: ssh2.c
155 ___________________________________________________________________
156 Modified: cvs2svn:cvs-rev
160 Index: libssh2/include/libssh2_publickey.h
161 ===================================================================
162 --- libssh2/include/libssh2_publickey.h (.../tags/RELEASE_0_11_0)
163 +++ libssh2/include/libssh2_publickey.h (.../trunk)
165 +/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
166 + * All rights reserved.
168 + * Redistribution and use in source and binary forms,
169 + * with or without modification, are permitted provided
170 + * that the following conditions are met:
172 + * Redistributions of source code must retain the above
173 + * copyright notice, this list of conditions and the
174 + * following disclaimer.
176 + * Redistributions in binary form must reproduce the above
177 + * copyright notice, this list of conditions and the following
178 + * disclaimer in the documentation and/or other materials
179 + * provided with the distribution.
181 + * Neither the name of the copyright holder nor the names
182 + * of any other contributors may be used to endorse or
183 + * promote products derived from this software without
184 + * specific prior written permission.
186 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
187 + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
188 + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
189 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
190 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
191 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
192 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
193 + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
194 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
195 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
196 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
197 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
198 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
202 +/* Note: This include file is only needed for using the
203 + * publickey SUBSYSTEM which is not the same as publickey
204 + * authentication. For authentication you only need libssh2.h
206 + * For more information on the publickey subsystem,
207 + * refer to IETF draft: secsh-publickey
210 +#ifndef LIBSSH2_PUBLICKEY_H
211 +#define LIBSSH2_PUBLICKEY_H 1
213 +typedef struct _LIBSSH2_PUBLICKEY LIBSSH2_PUBLICKEY;
215 +typedef struct _libssh2_publickey_attribute {
217 + unsigned long name_len;
219 + unsigned long value_len;
221 +} libssh2_publickey_attribute;
223 +typedef struct _libssh2_publickey_list {
224 + unsigned char *packet; /* For freeing */
226 + const unsigned char *name;
227 + unsigned long name_len;
228 + const unsigned char *blob;
229 + unsigned long blob_len;
230 + unsigned long num_attrs;
231 + libssh2_publickey_attribute *attrs; /* free me */
232 +} libssh2_publickey_list;
234 +/* Generally use the first macro here, but if both name and value are string literals, you can use _fast() to take advantage of preprocessing */
235 +#define libssh2_publickey_attribute(name, value, mandatory) { (name), strlen(name), (value), strlen(value), (mandatory) },
236 +#define libssh2_publickey_attribute_fast(name, value, mandatory) { (name), sizeof(name) - 1, (value), sizeof(value) - 1, (mandatory) },
242 +/* Publickey Subsystem */
243 +LIBSSH2_API LIBSSH2_PUBLICKEY *libssh2_publickey_init(LIBSSH2_SESSION *session);
245 +LIBSSH2_API int libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY *pkey, const unsigned char *name, unsigned long name_len,
246 + const unsigned char *blob, unsigned long blob_len, char overwrite,
247 + unsigned long num_attrs, const libssh2_publickey_attribute attrs[]);
248 +#define libssh2_publickey_add(pkey, name, blob, blob_len, overwrite, num_attrs, attrs) \
249 + libssh2_publickey_add_ex((pkey), (name), strlen(name), (blob), (blob_len), (overwrite), (num_attrs), (attrs))
251 +LIBSSH2_API int libssh2_publickey_remove_ex(LIBSSH2_PUBLICKEY *pkey, const unsigned char *name, unsigned long name_len,
252 + const unsigned char *blob, unsigned long blob_len);
253 +#define libssh2_publickey_remove(pkey, name, blob, blob_len) \
254 + libssh2_publickey_remove_ex((pkey), (name), strlen(name), (blob), (blob_len))
256 +LIBSSH2_API int libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY *pkey, unsigned long *num_keys, libssh2_publickey_list **pkey_list);
257 +LIBSSH2_API void libssh2_publickey_list_free(LIBSSH2_PUBLICKEY *pkey, libssh2_publickey_list *pkey_list);
259 +LIBSSH2_API int libssh2_publickey_shutdown(LIBSSH2_PUBLICKEY *pkey);
265 +#endif /* ndef: LIBSSH2_PUBLICKEY_H */
267 Property changes on: libssh2/include/libssh2_publickey.h
268 ___________________________________________________________________
272 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
273 Added: cvs2svn:cvs-rev
278 Index: libssh2/include/libssh2_sftp.h
279 ===================================================================
280 --- libssh2/include/libssh2_sftp.h (.../tags/RELEASE_0_11_0)
281 +++ libssh2/include/libssh2_sftp.h (.../trunk)
283 +/* Copyright (c) 2004-2008, Sara Golemon <sarag@libssh2.org>
284 + * All rights reserved.
286 + * Redistribution and use in source and binary forms,
287 + * with or without modification, are permitted provided
288 + * that the following conditions are met:
290 + * Redistributions of source code must retain the above
291 + * copyright notice, this list of conditions and the
292 + * following disclaimer.
294 + * Redistributions in binary form must reproduce the above
295 + * copyright notice, this list of conditions and the following
296 + * disclaimer in the documentation and/or other materials
297 + * provided with the distribution.
299 + * Neither the name of the copyright holder nor the names
300 + * of any other contributors may be used to endorse or
301 + * promote products derived from this software without
302 + * specific prior written permission.
304 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
305 + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
306 + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
307 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
308 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
309 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
310 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
311 + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
312 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
313 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
314 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
315 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
316 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
320 +#ifndef LIBSSH2_SFTP_H
321 +#define LIBSSH2_SFTP_H 1
331 +/* Note: Version 6 was documented at the time of writing
332 + * However it was marked as "DO NOT IMPLEMENT" due to pending changes
334 + * Let's start with Version 3 (The version found in OpenSSH) and go from there
336 +#define LIBSSH2_SFTP_VERSION 3
337 +#define LIBSSH2_SFTP_PACKET_MAXLEN 40000
339 +typedef struct _LIBSSH2_SFTP LIBSSH2_SFTP;
340 +typedef struct _LIBSSH2_SFTP_HANDLE LIBSSH2_SFTP_HANDLE;
341 +typedef struct _LIBSSH2_SFTP_ATTRIBUTES LIBSSH2_SFTP_ATTRIBUTES;
343 +/* Flags for open_ex() */
344 +#define LIBSSH2_SFTP_OPENFILE 0
345 +#define LIBSSH2_SFTP_OPENDIR 1
347 +/* Flags for rename_ex() */
348 +#define LIBSSH2_SFTP_RENAME_OVERWRITE 0x00000001
349 +#define LIBSSH2_SFTP_RENAME_ATOMIC 0x00000002
350 +#define LIBSSH2_SFTP_RENAME_NATIVE 0x00000004
352 +/* Flags for stat_ex() */
353 +#define LIBSSH2_SFTP_STAT 0
354 +#define LIBSSH2_SFTP_LSTAT 1
355 +#define LIBSSH2_SFTP_SETSTAT 2
357 +/* Flags for symlink_ex() */
358 +#define LIBSSH2_SFTP_SYMLINK 0
359 +#define LIBSSH2_SFTP_READLINK 1
360 +#define LIBSSH2_SFTP_REALPATH 2
362 +/* SFTP attribute flag bits */
363 +#define LIBSSH2_SFTP_ATTR_SIZE 0x00000001
364 +#define LIBSSH2_SFTP_ATTR_UIDGID 0x00000002
365 +#define LIBSSH2_SFTP_ATTR_PERMISSIONS 0x00000004
366 +#define LIBSSH2_SFTP_ATTR_ACMODTIME 0x00000008
367 +#define LIBSSH2_SFTP_ATTR_EXTENDED 0x80000000
369 +struct _LIBSSH2_SFTP_ATTRIBUTES {
370 + /* If flags & ATTR_* bit is set, then the value in this struct will be meaningful
371 + * Otherwise it should be ignored
373 + unsigned long flags;
375 + libssh2_uint64_t filesize;
376 + unsigned long uid, gid;
377 + unsigned long permissions;
378 + unsigned long atime, mtime;
381 +/* SFTP filetypes */
382 +#define LIBSSH2_SFTP_TYPE_REGULAR 1
383 +#define LIBSSH2_SFTP_TYPE_DIRECTORY 2
384 +#define LIBSSH2_SFTP_TYPE_SYMLINK 3
385 +#define LIBSSH2_SFTP_TYPE_SPECIAL 4
386 +#define LIBSSH2_SFTP_TYPE_UNKNOWN 5
387 +#define LIBSSH2_SFTP_TYPE_SOCKET 6
388 +#define LIBSSH2_SFTP_TYPE_CHAR_DEVICE 7
389 +#define LIBSSH2_SFTP_TYPE_BLOCK_DEVICE 8
390 +#define LIBSSH2_SFTP_TYPE_FIFO 9
393 + * Reproduce the POSIX file modes here for systems that are not
396 + * These is used in "permissions" of "struct _LIBSSH2_SFTP_ATTRIBUTES"
399 +#define LIBSSH2_SFTP_S_IFMT 0170000 /* type of file mask */
400 +#define LIBSSH2_SFTP_S_IFIFO 0010000 /* named pipe (fifo) */
401 +#define LIBSSH2_SFTP_S_IFCHR 0020000 /* character special */
402 +#define LIBSSH2_SFTP_S_IFDIR 0040000 /* directory */
403 +#define LIBSSH2_SFTP_S_IFBLK 0060000 /* block special */
404 +#define LIBSSH2_SFTP_S_IFREG 0100000 /* regular */
405 +#define LIBSSH2_SFTP_S_IFLNK 0120000 /* symbolic link */
406 +#define LIBSSH2_SFTP_S_IFSOCK 0140000 /* socket */
409 +/* Read, write, execute/search by owner */
410 +#define LIBSSH2_SFTP_S_IRWXU 0000700 /* RWX mask for owner */
411 +#define LIBSSH2_SFTP_S_IRUSR 0000400 /* R for owner */
412 +#define LIBSSH2_SFTP_S_IWUSR 0000200 /* W for owner */
413 +#define LIBSSH2_SFTP_S_IXUSR 0000100 /* X for owner */
414 +/* Read, write, execute/search by group */
415 +#define LIBSSH2_SFTP_S_IRWXG 0000070 /* RWX mask for group */
416 +#define LIBSSH2_SFTP_S_IRGRP 0000040 /* R for group */
417 +#define LIBSSH2_SFTP_S_IWGRP 0000020 /* W for group */
418 +#define LIBSSH2_SFTP_S_IXGRP 0000010 /* X for group */
419 +/* Read, write, execute/search by others */
420 +#define LIBSSH2_SFTP_S_IRWXO 0000007 /* RWX mask for other */
421 +#define LIBSSH2_SFTP_S_IROTH 0000004 /* R for other */
422 +#define LIBSSH2_SFTP_S_IWOTH 0000002 /* W for other */
423 +#define LIBSSH2_SFTP_S_IXOTH 0000001 /* X for other */
425 +/* SFTP File Transfer Flags -- (e.g. flags parameter to sftp_open())
426 + * Danger will robinson... APPEND doesn't have any effect on OpenSSH servers */
427 +#define LIBSSH2_FXF_READ 0x00000001
428 +#define LIBSSH2_FXF_WRITE 0x00000002
429 +#define LIBSSH2_FXF_APPEND 0x00000004
430 +#define LIBSSH2_FXF_CREAT 0x00000008
431 +#define LIBSSH2_FXF_TRUNC 0x00000010
432 +#define LIBSSH2_FXF_EXCL 0x00000020
434 +/* SFTP Status Codes (returned by libssh2_sftp_last_error() ) */
435 +#define LIBSSH2_FX_OK 0
436 +#define LIBSSH2_FX_EOF 1
437 +#define LIBSSH2_FX_NO_SUCH_FILE 2
438 +#define LIBSSH2_FX_PERMISSION_DENIED 3
439 +#define LIBSSH2_FX_FAILURE 4
440 +#define LIBSSH2_FX_BAD_MESSAGE 5
441 +#define LIBSSH2_FX_NO_CONNECTION 6
442 +#define LIBSSH2_FX_CONNECTION_LOST 7
443 +#define LIBSSH2_FX_OP_UNSUPPORTED 8
444 +#define LIBSSH2_FX_INVALID_HANDLE 9
445 +#define LIBSSH2_FX_NO_SUCH_PATH 10
446 +#define LIBSSH2_FX_FILE_ALREADY_EXISTS 11
447 +#define LIBSSH2_FX_WRITE_PROTECT 12
448 +#define LIBSSH2_FX_NO_MEDIA 13
449 +#define LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM 14
450 +#define LIBSSH2_FX_QUOTA_EXCEEDED 15
451 +#define LIBSSH2_FX_UNKNOWN_PRINCIPLE 16 /* Initial mis-spelling */
452 +#define LIBSSH2_FX_UNKNOWN_PRINCIPAL 16
453 +#define LIBSSH2_FX_LOCK_CONFlICT 17 /* Initial mis-spelling */
454 +#define LIBSSH2_FX_LOCK_CONFLICT 17
455 +#define LIBSSH2_FX_DIR_NOT_EMPTY 18
456 +#define LIBSSH2_FX_NOT_A_DIRECTORY 19
457 +#define LIBSSH2_FX_INVALID_FILENAME 20
458 +#define LIBSSH2_FX_LINK_LOOP 21
460 +/* Returned by any function that would block during a read/write opperation */
461 +#define LIBSSH2SFTP_EAGAIN LIBSSH2_ERROR_EAGAIN
464 +LIBSSH2_API LIBSSH2_SFTP *libssh2_sftp_init(LIBSSH2_SESSION *session);
465 +LIBSSH2_API int libssh2_sftp_shutdown(LIBSSH2_SFTP *sftp);
466 +LIBSSH2_API unsigned long libssh2_sftp_last_error(LIBSSH2_SFTP *sftp);
468 +/* File / Directory Ops */
469 +LIBSSH2_API LIBSSH2_SFTP_HANDLE *libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, const char *filename, unsigned int filename_len,
470 + unsigned long flags, long mode, int open_type);
471 +#define libssh2_sftp_open(sftp, filename, flags, mode) \
472 + libssh2_sftp_open_ex((sftp), (filename), strlen(filename), (flags), (mode), LIBSSH2_SFTP_OPENFILE)
473 +#define libssh2_sftp_opendir(sftp, path) \
474 + libssh2_sftp_open_ex((sftp), (path), strlen(path), 0, 0, LIBSSH2_SFTP_OPENDIR)
476 +LIBSSH2_API ssize_t libssh2_sftp_read(LIBSSH2_SFTP_HANDLE *handle, char *buffer, size_t buffer_maxlen);
478 +LIBSSH2_API int libssh2_sftp_readdir_ex(LIBSSH2_SFTP_HANDLE *handle, char *buffer, size_t buffer_maxlen,
479 + char *longentry, size_t longentry_maxlen,
480 + LIBSSH2_SFTP_ATTRIBUTES *attrs);
481 +#define libssh2_sftp_readdir(handle, buffer, buffer_maxlen, attrs) \
482 + libssh2_sftp_readdir_ex((handle), (buffer), (buffer_maxlen), NULL, 0, (attrs))
484 +LIBSSH2_API ssize_t libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *buffer, size_t count);
486 +LIBSSH2_API int libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle);
487 +#define libssh2_sftp_close(handle) libssh2_sftp_close_handle(handle)
488 +#define libssh2_sftp_closedir(handle) libssh2_sftp_close_handle(handle)
490 +LIBSSH2_API void libssh2_sftp_seek(LIBSSH2_SFTP_HANDLE *handle, size_t offset);
491 +LIBSSH2_API void libssh2_sftp_seek64(LIBSSH2_SFTP_HANDLE *handle, libssh2_uint64_t offset);
492 +#define libssh2_sftp_rewind(handle) libssh2_sftp_seek64((handle), 0)
494 +LIBSSH2_API size_t libssh2_sftp_tell(LIBSSH2_SFTP_HANDLE *handle);
495 +LIBSSH2_API libssh2_uint64_t libssh2_sftp_tell64(LIBSSH2_SFTP_HANDLE *handle);
497 +LIBSSH2_API int libssh2_sftp_fstat_ex(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP_ATTRIBUTES *attrs, int setstat);
498 +#define libssh2_sftp_fstat(handle, attrs) libssh2_sftp_fstat_ex((handle), (attrs), 0)
499 +#define libssh2_sftp_fsetstat(handle, attrs) libssh2_sftp_fstat_ex((handle), (attrs), 1)
503 +/* Miscellaneous Ops */
504 +LIBSSH2_API int libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp, const char *source_filename, unsigned int srouce_filename_len,
505 + const char *dest_filename, unsigned int dest_filename_len,
507 +#define libssh2_sftp_rename(sftp, sourcefile, destfile) libssh2_sftp_rename_ex((sftp), (sourcefile), strlen(sourcefile), (destfile), strlen(destfile), \
508 + LIBSSH2_SFTP_RENAME_OVERWRITE | LIBSSH2_SFTP_RENAME_ATOMIC | LIBSSH2_SFTP_RENAME_NATIVE)
510 +LIBSSH2_API int libssh2_sftp_unlink_ex(LIBSSH2_SFTP *sftp, const char *filename, unsigned int filename_len);
511 +#define libssh2_sftp_unlink(sftp, filename) libssh2_sftp_unlink_ex((sftp), (filename), strlen(filename))
513 +LIBSSH2_API int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, const char *path, unsigned int path_len, long mode);
514 +#define libssh2_sftp_mkdir(sftp, path, mode) libssh2_sftp_mkdir_ex((sftp), (path), strlen(path), (mode))
516 +LIBSSH2_API int libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp, const char *path, unsigned int path_len);
517 +#define libssh2_sftp_rmdir(sftp, path) libssh2_sftp_rmdir_ex((sftp), (path), strlen(path))
519 +LIBSSH2_API int libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp, const char *path, unsigned int path_len, int stat_type, LIBSSH2_SFTP_ATTRIBUTES *attrs);
520 +#define libssh2_sftp_stat(sftp, path, attrs) libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_STAT, (attrs))
521 +#define libssh2_sftp_lstat(sftp, path, attrs) libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_LSTAT, (attrs))
522 +#define libssh2_sftp_setstat(sftp, path, attrs) libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_SETSTAT, (attrs))
524 +LIBSSH2_API int libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, const char *path, unsigned int path_len, char *target, unsigned int target_len, int link_type);
525 +#define libssh2_sftp_symlink(sftp, orig, linkpath) libssh2_sftp_symlink_ex((sftp), (orig), strlen(orig), (linkpath), strlen(linkpath), LIBSSH2_SFTP_SYMLINK)
526 +#define libssh2_sftp_readlink(sftp, path, target, maxlen) libssh2_sftp_symlink_ex((sftp), (path), strlen(path), (target), (maxlen), LIBSSH2_SFTP_READLINK)
527 +#define libssh2_sftp_realpath(sftp, path, target, maxlen) libssh2_sftp_symlink_ex((sftp), (path), strlen(path), (target), (maxlen), LIBSSH2_SFTP_REALPATH)
533 +#endif /* LIBSSH2_SFTP_H */
535 Property changes on: libssh2/include/libssh2_sftp.h
536 ___________________________________________________________________
540 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
541 Added: cvs2svn:cvs-rev
546 Index: libssh2/include/libssh2.h
547 ===================================================================
548 --- libssh2/include/libssh2.h (.../tags/RELEASE_0_11_0)
549 +++ libssh2/include/libssh2.h (.../trunk)
551 +/* Copyright (c) 2004-2008, Sara Golemon <sarag@libssh2.org>
552 + * All rights reserved.
554 + * Redistribution and use in source and binary forms,
555 + * with or without modification, are permitted provided
556 + * that the following conditions are met:
558 + * Redistributions of source code must retain the above
559 + * copyright notice, this list of conditions and the
560 + * following disclaimer.
562 + * Redistributions in binary form must reproduce the above
563 + * copyright notice, this list of conditions and the following
564 + * disclaimer in the documentation and/or other materials
565 + * provided with the distribution.
567 + * Neither the name of the copyright holder nor the names
568 + * of any other contributors may be used to endorse or
569 + * promote products derived from this software without
570 + * specific prior written permission.
572 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
573 + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
574 + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
575 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
576 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
577 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
578 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
579 + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
580 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
581 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
582 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
583 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
584 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
597 +#include <sys/stat.h>
598 +#include <sys/types.h>
600 +/* Allow alternate API prefix from CFLAGS or calling app */
602 +# ifdef LIBSSH2_WIN32
603 +# ifdef LIBSSH2_LIBRARY
604 +# define LIBSSH2_API __declspec(dllexport)
606 +# define LIBSSH2_API __declspec(dllimport)
607 +# endif /* LIBSSH2_LIBRARY */
608 +# else /* !LIBSSH2_WIN32 */
609 +# define LIBSSH2_API
610 +# endif /* LIBSSH2_WIN32 */
611 +#endif /* LIBSSH2_API */
613 +#if defined(LIBSSH2_DARWIN) || (defined(LIBSSH2_WIN32) && !defined(_MSC_VER) && !defined(__MINGW32__))
614 +# include <sys/uio.h>
617 +#if (defined(NETWARE) && !defined(__NOVELL_LIBC__))
618 +# include <sys/bsdskt.h>
619 +typedef unsigned int uint32_t;
622 +#if defined(LIBSSH2_WIN32) && defined(_MSC_VER) && (_MSC_VER <= 1400)
623 +typedef unsigned __int64 libssh2_uint64_t;
624 +typedef __int64 libssh2_int64_t;
625 +typedef unsigned int uint32_t;
626 +#ifndef _SSIZE_T_DEFINED
627 +typedef int ssize_t;
628 +#define _SSIZE_T_DEFINED
631 +typedef unsigned long long libssh2_uint64_t;
632 +typedef long long libssh2_int64_t;
635 +/* We use underscore instead of dash when appending CVS in dev versions just
636 + to make the BANNER define (used by src/session.c) be a valid SSH
637 + banner. Release versions have no appended strings and may of coruse not
638 + have dashes either. */
639 +#define LIBSSH2_VERSION "1.0"
641 +/* The numeric version number is also available "in parts" by using these
643 +#define LIBSSH2_VERSION_MAJOR 1
644 +#define LIBSSH2_VERSION_MINOR 0
645 +#define LIBSSH2_VERSION_PATCH
647 +/* This is the numeric version of the libssh2 version number, meant for easier
648 + parsing and comparions by programs. The LIBSSH2_VERSION_NUM define will
649 + always follow this syntax:
653 + Where XX, YY and ZZ are the main version, release and patch numbers in
654 + hexadecimal (using 8 bits each). All three numbers are always represented
655 + using two digits. 1.2 would appear as "0x010200" while version 9.11.7
656 + appears as "0x090b07".
658 + This 6-digit (24 bits) hexadecimal number does not show pre-release number,
659 + and it is always a greater number in a more recent release. It makes
660 + comparisons with greater than and less than work.
662 +#define LIBSSH2_VERSION_NUM 0x010000
665 + * This is the date and time when the full source package was created. The
666 + * timestamp is not stored in CVS, as the timestamp is properly set in the
667 + * tarballs by the maketgz script.
669 + * The format of the date should follow this template:
671 + * "Mon Feb 12 11:35:33 UTC 2007"
673 +#define LIBSSH2_TIMESTAMP "Fri Dec 26 21:35:07 UTC 2008"
675 +/* Part of every banner, user specified or not */
676 +#define LIBSSH2_SSH_BANNER "SSH-2.0-libssh2_" LIBSSH2_VERSION
678 +/* We *could* add a comment here if we so chose */
679 +#define LIBSSH2_SSH_DEFAULT_BANNER LIBSSH2_SSH_BANNER
680 +#define LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF LIBSSH2_SSH_DEFAULT_BANNER "\r\n"
682 +/* Default generate and safe prime sizes for diffie-hellman-group-exchange-sha1 */
683 +#define LIBSSH2_DH_GEX_MINGROUP 1024
684 +#define LIBSSH2_DH_GEX_OPTGROUP 1536
685 +#define LIBSSH2_DH_GEX_MAXGROUP 2048
687 +/* Defaults for pty requests */
688 +#define LIBSSH2_TERM_WIDTH 80
689 +#define LIBSSH2_TERM_HEIGHT 24
690 +#define LIBSSH2_TERM_WIDTH_PX 0
691 +#define LIBSSH2_TERM_HEIGHT_PX 0
694 +#define LIBSSH2_SOCKET_POLL_UDELAY 250000
695 +/* 0.25 * 120 == 30 seconds */
696 +#define LIBSSH2_SOCKET_POLL_MAXLOOPS 120
698 +/* Maximum size to allow a payload to compress to, plays it safe by falling short of spec limits */
699 +#define LIBSSH2_PACKET_MAXCOMP 32000
701 +/* Maximum size to allow a payload to deccompress to, plays it safe by allowing more than spec requires */
702 +#define LIBSSH2_PACKET_MAXDECOMP 40000
704 +/* Maximum size for an inbound compressed payload, plays it safe by overshooting spec limits */
705 +#define LIBSSH2_PACKET_MAXPAYLOAD 40000
707 +/* Malloc callbacks */
708 +#define LIBSSH2_ALLOC_FUNC(name) void *name(size_t count, void **abstract)
709 +#define LIBSSH2_REALLOC_FUNC(name) void *name(void *ptr, size_t count, void **abstract)
710 +#define LIBSSH2_FREE_FUNC(name) void name(void *ptr, void **abstract)
712 +typedef struct _LIBSSH2_USERAUTH_KBDINT_PROMPT
715 + unsigned int length;
716 + unsigned char echo;
717 +} LIBSSH2_USERAUTH_KBDINT_PROMPT;
719 +typedef struct _LIBSSH2_USERAUTH_KBDINT_RESPONSE
722 + unsigned int length;
723 +} LIBSSH2_USERAUTH_KBDINT_RESPONSE;
725 +/* 'keyboard-interactive' authentication callback */
726 +#define LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC(name_) void name_(const char* name, int name_len, const char* instruction, int instruction_len, int num_prompts, const LIBSSH2_USERAUTH_KBDINT_PROMPT* prompts, LIBSSH2_USERAUTH_KBDINT_RESPONSE* responses, void **abstract)
728 +/* Callbacks for special SSH packets */
729 +#define LIBSSH2_IGNORE_FUNC(name) void name(LIBSSH2_SESSION *session, const char *message, int message_len, void **abstract)
730 +#define LIBSSH2_DEBUG_FUNC(name) void name(LIBSSH2_SESSION *session, int always_display, const char *message, int message_len, const char *language, int language_len,void **abstract)
731 +#define LIBSSH2_DISCONNECT_FUNC(name) void name(LIBSSH2_SESSION *session, int reason, const char *message, int message_len, const char *language, int language_len, void **abstract)
732 +#define LIBSSH2_PASSWD_CHANGEREQ_FUNC(name) void name(LIBSSH2_SESSION *session, char **newpw, int *newpw_len, void **abstract)
733 +#define LIBSSH2_MACERROR_FUNC(name) int name(LIBSSH2_SESSION *session, const char *packet, int packet_len, void **abstract)
734 +#define LIBSSH2_X11_OPEN_FUNC(name) void name(LIBSSH2_SESSION *session, LIBSSH2_CHANNEL *channel, const char *shost, int sport, void **abstract)
736 +#define LIBSSH2_CHANNEL_CLOSE_FUNC(name) void name(LIBSSH2_SESSION *session, void **session_abstract, LIBSSH2_CHANNEL *channel, void **channel_abstract)
738 +/* libssh2_session_callback_set() constants */
739 +#define LIBSSH2_CALLBACK_IGNORE 0
740 +#define LIBSSH2_CALLBACK_DEBUG 1
741 +#define LIBSSH2_CALLBACK_DISCONNECT 2
742 +#define LIBSSH2_CALLBACK_MACERROR 3
743 +#define LIBSSH2_CALLBACK_X11 4
745 +/* libssh2_session_method_pref() constants */
746 +#define LIBSSH2_METHOD_KEX 0
747 +#define LIBSSH2_METHOD_HOSTKEY 1
748 +#define LIBSSH2_METHOD_CRYPT_CS 2
749 +#define LIBSSH2_METHOD_CRYPT_SC 3
750 +#define LIBSSH2_METHOD_MAC_CS 4
751 +#define LIBSSH2_METHOD_MAC_SC 5
752 +#define LIBSSH2_METHOD_COMP_CS 6
753 +#define LIBSSH2_METHOD_COMP_SC 7
754 +#define LIBSSH2_METHOD_LANG_CS 8
755 +#define LIBSSH2_METHOD_LANG_SC 9
757 +/* session.flags bits */
758 +#define LIBSSH2_FLAG_SIGPIPE 0x00000001
760 +typedef struct _LIBSSH2_SESSION LIBSSH2_SESSION;
761 +typedef struct _LIBSSH2_CHANNEL LIBSSH2_CHANNEL;
762 +typedef struct _LIBSSH2_LISTENER LIBSSH2_LISTENER;
764 +typedef struct _LIBSSH2_POLLFD {
765 + unsigned char type; /* LIBSSH2_POLLFD_* below */
768 + int socket; /* File descriptors -- examined with system select() call */
769 + LIBSSH2_CHANNEL *channel; /* Examined by checking internal state */
770 + LIBSSH2_LISTENER *listener; /* Read polls only -- are inbound connections waiting to be accepted? */
773 + unsigned long events; /* Requested Events */
774 + unsigned long revents; /* Returned Events */
777 +/* Poll FD Descriptor Types */
778 +#define LIBSSH2_POLLFD_SOCKET 1
779 +#define LIBSSH2_POLLFD_CHANNEL 2
780 +#define LIBSSH2_POLLFD_LISTENER 3
782 +/* Note: Win32 Doesn't actually have a poll() implementation, so some of these values are faked with select() data */
783 +/* Poll FD events/revents -- Match sys/poll.h where possible */
784 +#define LIBSSH2_POLLFD_POLLIN 0x0001 /* Data available to be read or connection available -- All */
785 +#define LIBSSH2_POLLFD_POLLPRI 0x0002 /* Priority data available to be read -- Socket only */
786 +#define LIBSSH2_POLLFD_POLLEXT 0x0002 /* Extended data available to be read -- Channel only */
787 +#define LIBSSH2_POLLFD_POLLOUT 0x0004 /* Can may be written -- Socket/Channel */
789 +#define LIBSSH2_POLLFD_POLLERR 0x0008 /* Error Condition -- Socket */
790 +#define LIBSSH2_POLLFD_POLLHUP 0x0010 /* HangUp/EOF -- Socket */
791 +#define LIBSSH2_POLLFD_SESSION_CLOSED 0x0010 /* Session Disconnect */
792 +#define LIBSSH2_POLLFD_POLLNVAL 0x0020 /* Invalid request -- Socket Only */
793 +#define LIBSSH2_POLLFD_POLLEX 0x0040 /* Exception Condition -- Socket/Win32 */
794 +#define LIBSSH2_POLLFD_CHANNEL_CLOSED 0x0080 /* Channel Disconnect */
795 +#define LIBSSH2_POLLFD_LISTENER_CLOSED 0x0080 /* Listener Disconnect */
797 +#define HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION
798 +/* Block Direction Types */
799 +#define LIBSSH2_SESSION_BLOCK_INBOUND 0x0001
800 +#define LIBSSH2_SESSION_BLOCK_OUTBOUND 0x0002
803 +#define LIBSSH2_HOSTKEY_HASH_MD5 1
804 +#define LIBSSH2_HOSTKEY_HASH_SHA1 2
806 +/* Disconnect Codes (defined by SSH protocol) */
807 +#define SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT 1
808 +#define SSH_DISCONNECT_PROTOCOL_ERROR 2
809 +#define SSH_DISCONNECT_KEY_EXCHANGE_FAILED 3
810 +#define SSH_DISCONNECT_RESERVED 4
811 +#define SSH_DISCONNECT_MAC_ERROR 5
812 +#define SSH_DISCONNECT_COMPRESSION_ERROR 6
813 +#define SSH_DISCONNECT_SERVICE_NOT_AVAILABLE 7
814 +#define SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED 8
815 +#define SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE 9
816 +#define SSH_DISCONNECT_CONNECTION_LOST 10
817 +#define SSH_DISCONNECT_BY_APPLICATION 11
818 +#define SSH_DISCONNECT_TOO_MANY_CONNECTIONS 12
819 +#define SSH_DISCONNECT_AUTH_CANCELLED_BY_USER 13
820 +#define SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE 14
821 +#define SSH_DISCONNECT_ILLEGAL_USER_NAME 15
823 +/* Error Codes (defined by libssh2) */
824 +#define LIBSSH2_ERROR_NONE 0
825 +#define LIBSSH2_ERROR_SOCKET_NONE -1
826 +#define LIBSSH2_ERROR_BANNER_NONE -2
827 +#define LIBSSH2_ERROR_BANNER_SEND -3
828 +#define LIBSSH2_ERROR_INVALID_MAC -4
829 +#define LIBSSH2_ERROR_KEX_FAILURE -5
830 +#define LIBSSH2_ERROR_ALLOC -6
831 +#define LIBSSH2_ERROR_SOCKET_SEND -7
832 +#define LIBSSH2_ERROR_KEY_EXCHANGE_FAILURE -8
833 +#define LIBSSH2_ERROR_TIMEOUT -9
834 +#define LIBSSH2_ERROR_HOSTKEY_INIT -10
835 +#define LIBSSH2_ERROR_HOSTKEY_SIGN -11
836 +#define LIBSSH2_ERROR_DECRYPT -12
837 +#define LIBSSH2_ERROR_SOCKET_DISCONNECT -13
838 +#define LIBSSH2_ERROR_PROTO -14
839 +#define LIBSSH2_ERROR_PASSWORD_EXPIRED -15
840 +#define LIBSSH2_ERROR_FILE -16
841 +#define LIBSSH2_ERROR_METHOD_NONE -17
842 +#define LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED -18
843 +#define LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED -19
844 +#define LIBSSH2_ERROR_CHANNEL_OUTOFORDER -20
845 +#define LIBSSH2_ERROR_CHANNEL_FAILURE -21
846 +#define LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED -22
847 +#define LIBSSH2_ERROR_CHANNEL_UNKNOWN -23
848 +#define LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED -24
849 +#define LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED -25
850 +#define LIBSSH2_ERROR_CHANNEL_CLOSED -26
851 +#define LIBSSH2_ERROR_CHANNEL_EOF_SENT -27
852 +#define LIBSSH2_ERROR_SCP_PROTOCOL -28
853 +#define LIBSSH2_ERROR_ZLIB -29
854 +#define LIBSSH2_ERROR_SOCKET_TIMEOUT -30
855 +#define LIBSSH2_ERROR_SFTP_PROTOCOL -31
856 +#define LIBSSH2_ERROR_REQUEST_DENIED -32
857 +#define LIBSSH2_ERROR_METHOD_NOT_SUPPORTED -33
858 +#define LIBSSH2_ERROR_INVAL -34
859 +#define LIBSSH2_ERROR_INVALID_POLL_TYPE -35
860 +#define LIBSSH2_ERROR_PUBLICKEY_PROTOCOL -36
861 +#define LIBSSH2_ERROR_EAGAIN -37
864 +LIBSSH2_API LIBSSH2_SESSION *libssh2_session_init_ex(LIBSSH2_ALLOC_FUNC((*my_alloc)), LIBSSH2_FREE_FUNC((*my_free)), LIBSSH2_REALLOC_FUNC((*my_realloc)), void *abstract);
865 +#define libssh2_session_init() libssh2_session_init_ex(NULL, NULL, NULL, NULL)
866 +LIBSSH2_API void **libssh2_session_abstract(LIBSSH2_SESSION *session);
868 +LIBSSH2_API void *libssh2_session_callback_set(LIBSSH2_SESSION *session, int cbtype, void *callback);
869 +LIBSSH2_API int libssh2_banner_set(LIBSSH2_SESSION *session, const char *banner);
871 +LIBSSH2_API int libssh2_session_startup(LIBSSH2_SESSION *session, int sock);
872 +LIBSSH2_API int libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, int reason, const char *description, const char *lang);
873 +#define libssh2_session_disconnect(session, description) libssh2_session_disconnect_ex((session), SSH_DISCONNECT_BY_APPLICATION, (description), "")
874 +LIBSSH2_API int libssh2_session_free(LIBSSH2_SESSION *session);
876 +LIBSSH2_API const char *libssh2_hostkey_hash(LIBSSH2_SESSION *session, int hash_type);
878 +LIBSSH2_API int libssh2_session_method_pref(LIBSSH2_SESSION *session, int method_type, const char *prefs);
879 +LIBSSH2_API const char *libssh2_session_methods(LIBSSH2_SESSION *session, int method_type);
880 +LIBSSH2_API int libssh2_session_last_error(LIBSSH2_SESSION *session, char **errmsg, int *errmsg_len, int want_buf);
881 +LIBSSH2_API int libssh2_session_last_errno(LIBSSH2_SESSION *session);
882 +LIBSSH2_API int libssh2_session_block_directions(LIBSSH2_SESSION *session);
884 +LIBSSH2_API int libssh2_session_flag(LIBSSH2_SESSION *session, int flag, int value);
887 +LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, const char *username, unsigned int username_len);
888 +LIBSSH2_API int libssh2_userauth_authenticated(LIBSSH2_SESSION *session);
889 +LIBSSH2_API int libssh2_userauth_password_ex(LIBSSH2_SESSION *session, const char *username, unsigned int username_len, const char *password, unsigned int password_len, LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb)));
890 +#define libssh2_userauth_password(session, username, password) libssh2_userauth_password_ex((session), (username), strlen(username), (password), strlen(password), NULL)
892 +LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, const char *username, unsigned int username_len,
893 + const char *publickey, const char *privatekey,
894 + const char *passphrase);
895 +#define libssh2_userauth_publickey_fromfile(session, username, publickey, privatekey, passphrase) \
896 + libssh2_userauth_publickey_fromfile_ex((session), (username), strlen(username), (publickey), (privatekey), (passphrase))
897 +LIBSSH2_API int libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session, const char *username, unsigned int username_len,
898 + const char *publickey, const char *privatekey,
899 + const char *passphrase,
900 + const char *hostname, unsigned int hostname_len,
901 + const char *local_username, unsigned int local_username_len);
902 +#define libssh2_userauth_hostbased_fromfile(session, username, publickey, privatekey, passphrase, hostname) \
903 + libssh2_userauth_hostbased_fromfile_ex((session), (username), strlen(username), (publickey), (privatekey), (passphrase), (hostname), strlen(hostname), (username), strlen(username))
906 + * response_callback is provided with filled by library prompts array,
907 + * but client must allocate and fill individual responses. Responses
908 + * array is already allocated. Responses data will be freed by libssh2
909 + * after callback return, but before subsequent callback invokation.
911 +LIBSSH2_API int libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION* session, const char *username, unsigned int username_len,
912 + LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC((*response_callback)));
913 +#define libssh2_userauth_keyboard_interactive(session, username, response_callback) \
914 + libssh2_userauth_keyboard_interactive_ex((session), (username), strlen(username), (response_callback))
916 +LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds, long timeout);
919 +#define LIBSSH2_CHANNEL_WINDOW_DEFAULT 65536
920 +#define LIBSSH2_CHANNEL_PACKET_DEFAULT 16384
921 +#define LIBSSH2_CHANNEL_MINADJUST 1024
923 +/* Extended Data Handling */
924 +#define LIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL 0
925 +#define LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE 1
926 +#define LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE 2
928 +#define SSH_EXTENDED_DATA_STDERR 1
930 +/* Returned by any function that would block during a read/write opperation */
931 +#define LIBSSH2CHANNEL_EAGAIN LIBSSH2_ERROR_EAGAIN
933 +LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_open_ex(LIBSSH2_SESSION *session, const char *channel_type, unsigned int channel_type_len, unsigned int window_size, unsigned int packet_size, const char *message, unsigned int message_len);
934 +#define libssh2_channel_open_session(session) libssh2_channel_open_ex((session), "session", sizeof("session") - 1, LIBSSH2_CHANNEL_WINDOW_DEFAULT, LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0)
936 +LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *session, const char *host, int port, const char *shost, int sport);
937 +#define libssh2_channel_direct_tcpip(session, host, port) libssh2_channel_direct_tcpip_ex((session), (host), (port), "127.0.0.1", 22)
939 +LIBSSH2_API LIBSSH2_LISTENER *libssh2_channel_forward_listen_ex(LIBSSH2_SESSION *session, const char *host, int port, int *bound_port, int queue_maxsize);
940 +#define libssh2_channel_forward_listen(session, port) libssh2_channel_forward_listen_ex((session), NULL, (port), NULL, 16)
942 +LIBSSH2_API int libssh2_channel_forward_cancel(LIBSSH2_LISTENER *listener);
944 +LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_forward_accept(LIBSSH2_LISTENER *listener);
946 +LIBSSH2_API int libssh2_channel_setenv_ex(LIBSSH2_CHANNEL *channel, const char *varname, unsigned int varname_len, const char *value, unsigned int value_len);
947 +#define libssh2_channel_setenv(channel, varname, value) libssh2_channel_setenv_ex((channel), (varname), strlen(varname), (value), strlen(value))
949 +LIBSSH2_API int libssh2_channel_request_pty_ex(LIBSSH2_CHANNEL *channel, const char *term, unsigned int term_len, const char *modes, unsigned int modes_len, int width, int height, int width_px, int height_px);
950 +#define libssh2_channel_request_pty(channel, term) libssh2_channel_request_pty_ex((channel), (term), strlen(term), NULL, 0, LIBSSH2_TERM_WIDTH, LIBSSH2_TERM_HEIGHT, LIBSSH2_TERM_WIDTH_PX, LIBSSH2_TERM_HEIGHT_PX)
952 +LIBSSH2_API int libssh2_channel_request_pty_size_ex(LIBSSH2_CHANNEL * channel, int width, int height, int width_px, int height_px);
953 +#define libssh2_channel_request_pty_size(channel, width, height) libssh2_channel_request_pty_size_ex( (channel), (width), (height), 0, 0)
955 +LIBSSH2_API int libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL *channel, int single_connection, const char *auth_proto, const char *auth_cookie, int screen_number);
956 +#define libssh2_channel_x11_req(channel, screen_number) libssh2_channel_x11_req_ex((channel), 0, NULL, NULL, (screen_number))
958 +LIBSSH2_API int libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, const char *request, unsigned int request_len, const char *message, unsigned int message_len);
959 +#define libssh2_channel_shell(channel) libssh2_channel_process_startup((channel), "shell", sizeof("shell") - 1, NULL, 0)
960 +#define libssh2_channel_exec(channel, command) libssh2_channel_process_startup((channel), "exec", sizeof("exec") - 1, (command), strlen(command))
961 +#define libssh2_channel_subsystem(channel, subsystem) libssh2_channel_process_startup((channel), "subsystem", sizeof("subsystem") - 1, (subsystem), strlen(subsystem))
963 +LIBSSH2_API ssize_t libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id, char *buf, size_t buflen);
964 +#define libssh2_channel_read(channel, buf, buflen) \
965 + libssh2_channel_read_ex((channel), 0, (buf), (buflen))
966 +#define libssh2_channel_read_stderr(channel, buf, buflen) \
967 + libssh2_channel_read_ex((channel), SSH_EXTENDED_DATA_STDERR, (buf), (buflen))
969 +LIBSSH2_API int libssh2_poll_channel_read(LIBSSH2_CHANNEL *channel, int extended);
971 +LIBSSH2_API unsigned long libssh2_channel_window_read_ex(LIBSSH2_CHANNEL *channel, unsigned long *read_avail, unsigned long *window_size_initial);
972 +#define libssh2_channel_window_read(channel) \
973 + libssh2_channel_window_read_ex((channel), NULL, NULL)
975 +LIBSSH2_API unsigned long libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL *channel, unsigned long adjustment, unsigned char force);
977 +LIBSSH2_API ssize_t libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel, int stream_id, const char *buf, size_t buflen);
979 +#define libssh2_channel_write(channel, buf, buflen) \
980 + libssh2_channel_write_ex((channel), 0, (buf), (buflen))
981 +#define libssh2_channel_write_stderr(channel, buf, buflen) \
982 + libssh2_channel_write_ex((channel), SSH_EXTENDED_DATA_STDERR, (buf), (buflen))
984 +LIBSSH2_API unsigned long libssh2_channel_window_write_ex(LIBSSH2_CHANNEL *channel, unsigned long *window_size_initial);
985 +#define libssh2_channel_window_write(channel) libssh2_channel_window_write_ex((channel), NULL)
987 +LIBSSH2_API void libssh2_session_set_blocking(LIBSSH2_SESSION* session, int blocking);
988 +LIBSSH2_API int libssh2_session_get_blocking(LIBSSH2_SESSION* session);
990 +LIBSSH2_API void libssh2_channel_set_blocking(LIBSSH2_CHANNEL *channel, int blocking);
992 +LIBSSH2_API void libssh2_channel_handle_extended_data(LIBSSH2_CHANNEL *channel, int ignore_mode);
993 +LIBSSH2_API int libssh2_channel_handle_extended_data2(LIBSSH2_CHANNEL *channel, int ignore_mode);
994 +/* libssh2_channel_ignore_extended_data() is defined below for BC with version 0.1
995 + * Future uses should use libssh2_channel_handle_extended_data() directly
996 + * if LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE is passed, extended data will be read (FIFO) from the standard data channel
999 +#define libssh2_channel_ignore_extended_data(channel, ignore) libssh2_channel_handle_extended_data((channel), (ignore) ? LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE : LIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL )
1001 +#define LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA -1
1002 +#define LIBSSH2_CHANNEL_FLUSH_ALL -2
1003 +LIBSSH2_API int libssh2_channel_flush_ex(LIBSSH2_CHANNEL *channel, int streamid);
1004 +#define libssh2_channel_flush(channel) libssh2_channel_flush_ex((channel), 0)
1005 +#define libssh2_channel_flush_stderr(channel) libssh2_channel_flush_ex((channel), SSH_EXTENDED_DATA_STDERR)
1006 +LIBSSH2_API int libssh2_channel_get_exit_status(LIBSSH2_CHANNEL* channel);
1008 +LIBSSH2_API int libssh2_channel_send_eof(LIBSSH2_CHANNEL *channel);
1009 +LIBSSH2_API int libssh2_channel_eof(LIBSSH2_CHANNEL *channel);
1010 +LIBSSH2_API int libssh2_channel_wait_eof(LIBSSH2_CHANNEL *channel);
1011 +LIBSSH2_API int libssh2_channel_close(LIBSSH2_CHANNEL *channel);
1012 +LIBSSH2_API int libssh2_channel_wait_closed(LIBSSH2_CHANNEL *channel);
1013 +LIBSSH2_API int libssh2_channel_free(LIBSSH2_CHANNEL *channel);
1015 +LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, const char *path, struct stat *sb);
1016 +LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, const char *path, int mode, size_t size, long mtime, long atime);
1017 +#define libssh2_scp_send(session, path, mode, size) libssh2_scp_send_ex((session), (path), (mode), (size), 0, 0)
1019 +LIBSSH2_API int libssh2_base64_decode(LIBSSH2_SESSION *session, char **dest, unsigned int *dest_len, const char *src, unsigned int src_len);
1022 + libssh2_trace() has no function in builds that aren't built with debug
1025 +LIBSSH2_API int libssh2_trace(LIBSSH2_SESSION *session, int bitmask);
1026 +#define LIBSSH2_TRACE_TRANS (1<<1)
1027 +#define LIBSSH2_TRACE_KEX (1<<2)
1028 +#define LIBSSH2_TRACE_AUTH (1<<3)
1029 +#define LIBSSH2_TRACE_CONN (1<<4)
1030 +#define LIBSSH2_TRACE_SCP (1<<5)
1031 +#define LIBSSH2_TRACE_SFTP (1<<6)
1032 +#define LIBSSH2_TRACE_ERROR (1<<7)
1033 +#define LIBSSH2_TRACE_PUBLICKEY (1<<8)
1039 +#endif /* LIBSSH2_H */
1041 Property changes on: libssh2/include/libssh2.h
1042 ___________________________________________________________________
1043 Added: svn:mime-type
1046 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
1047 Added: cvs2svn:cvs-rev
1049 Added: svn:eol-style
1052 Index: libssh2/src/comp.c
1053 ===================================================================
1054 --- libssh2/src/comp.c (.../tags/RELEASE_0_11_0)
1055 +++ libssh2/src/comp.c (.../trunk)
1057 +/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
1058 + * All rights reserved.
1060 + * Redistribution and use in source and binary forms,
1061 + * with or without modification, are permitted provided
1062 + * that the following conditions are met:
1064 + * Redistributions of source code must retain the above
1065 + * copyright notice, this list of conditions and the
1066 + * following disclaimer.
1068 + * Redistributions in binary form must reproduce the above
1069 + * copyright notice, this list of conditions and the following
1070 + * disclaimer in the documentation and/or other materials
1071 + * provided with the distribution.
1073 + * Neither the name of the copyright holder nor the names
1074 + * of any other contributors may be used to endorse or
1075 + * promote products derived from this software without
1076 + * specific prior written permission.
1078 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
1079 + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
1080 + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1081 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1082 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
1083 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1084 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
1085 + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
1086 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
1087 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
1088 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
1089 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
1090 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
1094 +#include "libssh2_priv.h"
1095 +#ifdef LIBSSH2_HAVE_ZLIB
1103 +/* {{{ libssh2_comp_method_none_comp
1104 + * Minimalist compression: Absolutely none
1107 +libssh2_comp_method_none_comp(LIBSSH2_SESSION * session,
1109 + unsigned char **dest,
1110 + unsigned long *dest_len,
1111 + unsigned long payload_limit,
1113 + const unsigned char *src,
1114 + unsigned long src_len, void **abstract)
1118 + (void) payload_limit;
1120 + *dest = (unsigned char *) src;
1121 + *dest_len = src_len;
1130 +static const LIBSSH2_COMP_METHOD libssh2_comp_method_none = {
1133 + libssh2_comp_method_none_comp,
1137 +#ifdef LIBSSH2_HAVE_ZLIB
1142 +/* {{{ Memory management wrappers
1143 + * Yes, I realize we're doing a callback to a callback,
1148 +libssh2_comp_method_zlib_alloc(voidpf opaque, uInt items, uInt size)
1150 + LIBSSH2_SESSION *session = (LIBSSH2_SESSION *) opaque;
1152 + return (voidpf) LIBSSH2_ALLOC(session, items * size);
1156 +libssh2_comp_method_zlib_free(voidpf opaque, voidpf address)
1158 + LIBSSH2_SESSION *session = (LIBSSH2_SESSION *) opaque;
1160 + LIBSSH2_FREE(session, address);
1165 +/* {{{ libssh2_comp_method_zlib_init
1166 + * All your bandwidth are belong to us (so save some)
1169 +libssh2_comp_method_zlib_init(LIBSSH2_SESSION * session, int compress,
1175 + strm = LIBSSH2_ALLOC(session, sizeof(z_stream));
1177 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
1178 + "Unable to allocate memory for zlib compression/decompression",
1182 + memset(strm, 0, sizeof(z_stream));
1184 + strm->opaque = (voidpf) session;
1185 + strm->zalloc = (alloc_func) libssh2_comp_method_zlib_alloc;
1186 + strm->zfree = (free_func) libssh2_comp_method_zlib_free;
1189 + status = deflateInit(strm, Z_DEFAULT_COMPRESSION);
1192 + status = inflateInit(strm);
1195 + if (status != Z_OK) {
1196 + LIBSSH2_FREE(session, strm);
1206 +/* {{{ libssh2_comp_method_zlib_comp
1207 + * zlib, a compression standard for all occasions
1210 +libssh2_comp_method_zlib_comp(LIBSSH2_SESSION * session,
1212 + unsigned char **dest,
1213 + unsigned long *dest_len,
1214 + unsigned long payload_limit,
1216 + const unsigned char *src,
1217 + unsigned long src_len, void **abstract)
1219 + z_stream *strm = *abstract;
1220 + /* A short-term alloc of a full data chunk is better than a series of
1223 + int out_maxlen = compress ? (src_len + 4) : (2 * src_len);
1226 + /* In practice they never come smaller than this */
1227 + if (out_maxlen < 25) {
1231 + if (out_maxlen > (int) payload_limit) {
1232 + out_maxlen = payload_limit;
1235 + strm->next_in = (unsigned char *) src;
1236 + strm->avail_in = src_len;
1237 + strm->next_out = (unsigned char *) LIBSSH2_ALLOC(session, out_maxlen);
1238 + out = (char *) strm->next_out;
1239 + strm->avail_out = out_maxlen;
1240 + if (!strm->next_out) {
1241 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
1242 + "Unable to allocate compression/decompression buffer",
1246 + while (strm->avail_in) {
1250 + status = deflate(strm, Z_PARTIAL_FLUSH);
1252 + status = inflate(strm, Z_PARTIAL_FLUSH);
1254 + if (status != Z_OK) {
1255 + libssh2_error(session, LIBSSH2_ERROR_ZLIB,
1256 + "compress/decompression failure", 0);
1257 + LIBSSH2_FREE(session, out);
1260 + if (strm->avail_in) {
1261 + unsigned long out_ofs = out_maxlen - strm->avail_out;
1265 + compress ? (strm->avail_in + 4) : (2 * strm->avail_in);
1267 + if ((out_maxlen > (int) payload_limit) && !compress && limiter++) {
1268 + libssh2_error(session, LIBSSH2_ERROR_ZLIB,
1269 + "Excessive growth in decompression phase", 0);
1270 + LIBSSH2_FREE(session, out);
1274 + newout = LIBSSH2_REALLOC(session, out, out_maxlen);
1276 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
1277 + "Unable to expand compress/decompression buffer",
1279 + LIBSSH2_FREE(session, out);
1283 + strm->next_out = (unsigned char *) out + out_ofs;
1284 + strm->avail_out +=
1285 + compress ? (strm->avail_in + 4) : (2 * strm->avail_in);
1287 + while (!strm->avail_out) {
1288 + /* Done with input, might be a byte or two in internal buffer during compress
1289 + * Or potentially many bytes if it's a decompress
1291 + int grow_size = compress ? 8 : 1024;
1294 + if (out_maxlen >= (int) payload_limit) {
1295 + libssh2_error(session, LIBSSH2_ERROR_ZLIB,
1296 + "Excessive growth in decompression phase",
1298 + LIBSSH2_FREE(session, out);
1302 + if (grow_size > (int) (payload_limit - out_maxlen)) {
1303 + grow_size = payload_limit - out_maxlen;
1306 + out_maxlen += grow_size;
1307 + strm->avail_out = grow_size;
1309 + newout = LIBSSH2_REALLOC(session, out, out_maxlen);
1311 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
1312 + "Unable to expand final compress/decompress buffer",
1314 + LIBSSH2_FREE(session, out);
1318 + strm->next_out = (unsigned char *) out + out_maxlen -
1322 + status = deflate(strm, Z_PARTIAL_FLUSH);
1324 + status = inflate(strm, Z_PARTIAL_FLUSH);
1326 + if (status != Z_OK) {
1327 + libssh2_error(session, LIBSSH2_ERROR_ZLIB,
1328 + "compress/decompression failure", 0);
1329 + LIBSSH2_FREE(session, out);
1335 + *dest = (unsigned char *) out;
1336 + *dest_len = out_maxlen - strm->avail_out;
1344 +/* {{{ libssh2_comp_method_zlib_dtor
1345 + * All done, no more compression for you
1348 +libssh2_comp_method_zlib_dtor(LIBSSH2_SESSION * session, int compress,
1351 + z_stream *strm = *abstract;
1362 + LIBSSH2_FREE(session, strm);
1372 +static const LIBSSH2_COMP_METHOD libssh2_comp_method_zlib = {
1374 + libssh2_comp_method_zlib_init,
1375 + libssh2_comp_method_zlib_comp,
1376 + libssh2_comp_method_zlib_dtor,
1378 +#endif /* LIBSSH2_HAVE_ZLIB */
1380 +/* ***********************
1381 + * Compression Methods *
1382 + *********************** */
1384 +static const LIBSSH2_COMP_METHOD *_libssh2_comp_methods[] = {
1385 + &libssh2_comp_method_none,
1386 +#ifdef LIBSSH2_HAVE_ZLIB
1387 + &libssh2_comp_method_zlib,
1388 +#endif /* LIBSSH2_HAVE_ZLIB */
1392 +const LIBSSH2_COMP_METHOD **
1393 +libssh2_comp_methods(void)
1395 + return _libssh2_comp_methods;
1398 Property changes on: libssh2/src/comp.c
1399 ___________________________________________________________________
1400 Added: svn:mime-type
1403 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
1404 Added: cvs2svn:cvs-rev
1406 Added: svn:eol-style
1409 Index: libssh2/src/libgcrypt.c
1410 ===================================================================
1411 --- libssh2/src/libgcrypt.c (.../tags/RELEASE_0_11_0)
1412 +++ libssh2/src/libgcrypt.c (.../trunk)
1414 +/* Copyright (C) 2006, 2007, The Written Word, Inc.
1415 + * Copyright (C) 2008, Simon Josefsson
1416 + * All rights reserved.
1418 + * Redistribution and use in source and binary forms,
1419 + * with or without modification, are permitted provided
1420 + * that the following conditions are met:
1422 + * Redistributions of source code must retain the above
1423 + * copyright notice, this list of conditions and the
1424 + * following disclaimer.
1426 + * Redistributions in binary form must reproduce the above
1427 + * copyright notice, this list of conditions and the following
1428 + * disclaimer in the documentation and/or other materials
1429 + * provided with the distribution.
1431 + * Neither the name of the copyright holder nor the names
1432 + * of any other contributors may be used to endorse or
1433 + * promote products derived from this software without
1434 + * specific prior written permission.
1436 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
1437 + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
1438 + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1439 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1440 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
1441 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1442 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
1443 + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
1444 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
1445 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
1446 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
1447 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
1448 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
1452 +#include "libssh2_priv.h"
1453 +#include <string.h>
1456 +_libssh2_rsa_new(libssh2_rsa_ctx ** rsa,
1457 + const unsigned char *edata,
1458 + unsigned long elen,
1459 + const unsigned char *ndata,
1460 + unsigned long nlen,
1461 + const unsigned char *ddata,
1462 + unsigned long dlen,
1463 + const unsigned char *pdata,
1464 + unsigned long plen,
1465 + const unsigned char *qdata,
1466 + unsigned long qlen,
1467 + const unsigned char *e1data,
1468 + unsigned long e1len,
1469 + const unsigned char *e2data,
1470 + unsigned long e2len,
1471 + const unsigned char *coeffdata, unsigned long coefflen)
1480 + rc = gcry_sexp_build
1482 + "(private-key(rsa(n%b)(e%b)(d%b)(q%b)(p%b)(u%b)))",
1483 + nlen, ndata, elen, edata, dlen, ddata, plen, pdata,
1484 + qlen, qdata, coefflen, coeffdata);
1486 + rc = gcry_sexp_build(rsa, NULL, "(public-key(rsa(n%b)(e%b)))",
1487 + nlen, ndata, elen, edata);
1498 +_libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsa,
1499 + const unsigned char *sig,
1500 + unsigned long sig_len,
1501 + const unsigned char *m, unsigned long m_len)
1503 + unsigned char hash[SHA_DIGEST_LENGTH];
1504 + gcry_sexp_t s_sig, s_hash;
1507 + libssh2_sha1(m, m_len, hash);
1509 + rc = gcry_sexp_build(&s_hash, NULL,
1510 + "(data (flags pkcs1) (hash sha1 %b))",
1511 + SHA_DIGEST_LENGTH, hash);
1516 + rc = gcry_sexp_build(&s_sig, NULL, "(sig-val(rsa(s %b)))", sig_len, sig);
1518 + gcry_sexp_release(s_hash);
1522 + rc = gcry_pk_verify(s_sig, s_hash, rsa);
1523 + gcry_sexp_release(s_sig);
1524 + gcry_sexp_release(s_hash);
1526 + return (rc == 0) ? 0 : -1;
1530 +_libssh2_dsa_new(libssh2_dsa_ctx ** dsactx,
1531 + const unsigned char *p,
1532 + unsigned long p_len,
1533 + const unsigned char *q,
1534 + unsigned long q_len,
1535 + const unsigned char *g,
1536 + unsigned long g_len,
1537 + const unsigned char *y,
1538 + unsigned long y_len,
1539 + const unsigned char *x, unsigned long x_len)
1544 + rc = gcry_sexp_build
1546 + "(private-key(dsa(p%b)(q%b)(g%b)(y%b)(x%b)))",
1547 + p_len, p, q_len, q, g_len, g, y_len, y, x_len, x);
1549 + rc = gcry_sexp_build(dsactx, NULL,
1550 + "(public-key(dsa(p%b)(q%b)(g%b)(y%b)))",
1551 + p_len, p, q_len, q, g_len, g, y_len, y);
1563 +_libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa,
1564 + LIBSSH2_SESSION * session,
1565 + FILE * fp, unsigned const char *passphrase)
1567 + unsigned char *data, *save_data;
1568 + unsigned int datalen;
1570 + unsigned char *n, *e, *d, *p, *q, *e1, *e2, *coeff;
1571 + unsigned int nlen, elen, dlen, plen, qlen, e1len, e2len, coefflen;
1573 + (void) passphrase;
1575 + ret = _libssh2_pem_parse(session,
1576 + "-----BEGIN RSA PRIVATE KEY-----",
1577 + "-----END RSA PRIVATE KEY-----",
1578 + fp, &data, &datalen);
1585 + if (_libssh2_pem_decode_sequence(&data, &datalen)) {
1589 +/* First read Version field (should be 0). */
1590 + ret = _libssh2_pem_decode_integer(&data, &datalen, &n, &nlen);
1591 + if (ret != 0 || (nlen != 1 && *n != '\0')) {
1596 + ret = _libssh2_pem_decode_integer(&data, &datalen, &n, &nlen);
1602 + ret = _libssh2_pem_decode_integer(&data, &datalen, &e, &elen);
1608 + ret = _libssh2_pem_decode_integer(&data, &datalen, &d, &dlen);
1614 + ret = _libssh2_pem_decode_integer(&data, &datalen, &p, &plen);
1620 + ret = _libssh2_pem_decode_integer(&data, &datalen, &q, &qlen);
1626 + ret = _libssh2_pem_decode_integer(&data, &datalen, &e1, &e1len);
1632 + ret = _libssh2_pem_decode_integer(&data, &datalen, &e2, &e2len);
1638 + ret = _libssh2_pem_decode_integer(&data, &datalen, &coeff, &coefflen);
1644 + if (_libssh2_rsa_new(rsa, e, elen, n, nlen, d, dlen, p, plen,
1645 + q, qlen, e1, e1len, e2, e2len, coeff, coefflen)) {
1653 + LIBSSH2_FREE(session, save_data);
1658 +_libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa,
1659 + LIBSSH2_SESSION * session,
1660 + FILE * fp, unsigned const char *passphrase)
1662 + unsigned char *data, *save_data;
1663 + unsigned int datalen;
1665 + unsigned char *p, *q, *g, *y, *x;
1666 + unsigned int plen, qlen, glen, ylen, xlen;
1668 + (void) passphrase;
1670 + ret = _libssh2_pem_parse(session,
1671 + "-----BEGIN DSA PRIVATE KEY-----",
1672 + "-----END DSA PRIVATE KEY-----",
1673 + fp, &data, &datalen);
1680 + if (_libssh2_pem_decode_sequence(&data, &datalen)) {
1685 +/* First read Version field (should be 0). */
1686 + ret = _libssh2_pem_decode_integer(&data, &datalen, &p, &plen);
1687 + if (ret != 0 || (plen != 1 && *p != '\0')) {
1692 + ret = _libssh2_pem_decode_integer(&data, &datalen, &p, &plen);
1698 + ret = _libssh2_pem_decode_integer(&data, &datalen, &q, &qlen);
1704 + ret = _libssh2_pem_decode_integer(&data, &datalen, &g, &glen);
1710 + ret = _libssh2_pem_decode_integer(&data, &datalen, &y, &ylen);
1716 + ret = _libssh2_pem_decode_integer(&data, &datalen, &x, &xlen);
1722 + if (datalen != 0) {
1727 + if (_libssh2_dsa_new(dsa, p, plen, q, qlen, g, glen, y, ylen, x, xlen)) {
1735 + LIBSSH2_FREE(session, save_data);
1740 +_libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session,
1741 + libssh2_dsa_ctx * rsactx,
1742 + const unsigned char *hash,
1743 + unsigned long hash_len,
1744 + unsigned char **signature, unsigned long *signature_len)
1746 + gcry_sexp_t sig_sexp;
1752 + if (hash_len != SHA_DIGEST_LENGTH) {
1756 + if (gcry_sexp_build(&data, NULL,
1757 + "(data (flags pkcs1) (hash sha1 %b))",
1758 + hash_len, hash)) {
1762 + rc = gcry_pk_sign(&sig_sexp, data, rsactx);
1764 + gcry_sexp_release(data);
1770 + data = gcry_sexp_find_token(sig_sexp, "s", 0);
1775 + tmp = gcry_sexp_nth_data(data, 1, &size);
1780 + if (tmp[0] == '\0') {
1785 + *signature = LIBSSH2_ALLOC(session, size);
1786 + memcpy(*signature, tmp, size);
1787 + *signature_len = size;
1793 +_libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,
1794 + const unsigned char *hash,
1795 + unsigned long hash_len, unsigned char *sig)
1797 + unsigned char zhash[SHA_DIGEST_LENGTH + 1];
1798 + gcry_sexp_t sig_sexp;
1804 + if (hash_len != SHA_DIGEST_LENGTH) {
1808 + memcpy(zhash + 1, hash, hash_len);
1811 + if (gcry_sexp_build(&data, NULL, "(data (value %b))", hash_len + 1, zhash)) {
1815 + ret = gcry_pk_sign(&sig_sexp, data, dsactx);
1817 + gcry_sexp_release(data);
1825 + data = gcry_sexp_find_token(sig_sexp, "r", 0);
1831 + tmp = gcry_sexp_nth_data(data, 1, &size);
1837 + if (tmp[0] == '\0') {
1847 + memcpy(sig, tmp, 20);
1849 + gcry_sexp_release(data);
1853 + data = gcry_sexp_find_token(sig_sexp, "s", 0);
1859 + tmp = gcry_sexp_nth_data(data, 1, &size);
1865 + if (tmp[0] == '\0') {
1875 + memcpy(sig + 20, tmp, 20);
1880 + gcry_sexp_release(sig_sexp);
1883 + gcry_sexp_release(data);
1889 +_libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx,
1890 + const unsigned char *sig,
1891 + const unsigned char *m, unsigned long m_len)
1893 + unsigned char hash[SHA_DIGEST_LENGTH + 1];
1894 + gcry_sexp_t s_sig, s_hash;
1897 + libssh2_sha1(m, m_len, hash + 1);
1900 + if (gcry_sexp_build(&s_hash, NULL, "(data(flags raw)(value %b))",
1901 + SHA_DIGEST_LENGTH + 1, hash)) {
1905 + if (gcry_sexp_build(&s_sig, NULL, "(sig-val(dsa(r %b)(s %b)))",
1906 + 20, sig, 20, sig + 20)) {
1907 + gcry_sexp_release(s_hash);
1911 + rc = gcry_pk_verify(s_sig, s_hash, dsactx);
1912 + gcry_sexp_release(s_sig);
1913 + gcry_sexp_release(s_hash);
1915 + return (rc == 0) ? 0 : -1;
1919 +_libssh2_cipher_init(_libssh2_cipher_ctx * h,
1920 + _libssh2_cipher_type(algo),
1921 + unsigned char *iv, unsigned char *secret, int encrypt)
1923 + int mode = 0, ret;
1924 + int keylen = gcry_cipher_get_algo_keylen(algo);
1928 + if (algo != GCRY_CIPHER_ARCFOUR) {
1929 + mode = GCRY_CIPHER_MODE_CBC;
1932 + ret = gcry_cipher_open(h, algo, mode, 0);
1937 + ret = gcry_cipher_setkey(*h, secret, keylen);
1939 + gcry_cipher_close(*h);
1943 + if (algo != GCRY_CIPHER_ARCFOUR) {
1944 + int blklen = gcry_cipher_get_algo_blklen(algo);
1945 + ret = gcry_cipher_setiv(*h, iv, blklen);
1947 + gcry_cipher_close(*h);
1956 +_libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx,
1957 + _libssh2_cipher_type(algo),
1958 + int encrypt, unsigned char *block)
1960 + size_t blklen = gcry_cipher_get_algo_blklen(algo);
1962 + if (blklen == 1) {
1963 +/* Hack for arcfour. */
1968 + ret = gcry_cipher_encrypt(*ctx, block, blklen, block, blklen);
1970 + ret = gcry_cipher_decrypt(*ctx, block, blklen, block, blklen);
1975 Property changes on: libssh2/src/libgcrypt.c
1976 ___________________________________________________________________
1977 Added: svn:mime-type
1980 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
1981 Added: cvs2svn:cvs-rev
1983 Added: svn:eol-style
1985 Added: svn:executable
1988 Index: libssh2/src/userauth.c
1989 ===================================================================
1990 --- libssh2/src/userauth.c (.../tags/RELEASE_0_11_0)
1991 +++ libssh2/src/userauth.c (.../trunk)
1993 +/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
1994 + * All rights reserved.
1996 + * Redistribution and use in source and binary forms,
1997 + * with or without modification, are permitted provided
1998 + * that the following conditions are met:
2000 + * Redistributions of source code must retain the above
2001 + * copyright notice, this list of conditions and the
2002 + * following disclaimer.
2004 + * Redistributions in binary form must reproduce the above
2005 + * copyright notice, this list of conditions and the following
2006 + * disclaimer in the documentation and/or other materials
2007 + * provided with the distribution.
2009 + * Neither the name of the copyright holder nor the names
2010 + * of any other contributors may be used to endorse or
2011 + * promote products derived from this software without
2012 + * specific prior written permission.
2014 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
2015 + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
2016 + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2017 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2018 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
2019 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2020 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2021 + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2022 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2023 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2024 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
2025 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
2026 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
2030 +#include "libssh2_priv.h"
2035 +/* Needed for struct iovec on some platforms */
2036 +#ifdef HAVE_SYS_UIO_H
2037 +#include <sys/uio.h>
2041 +/* {{{ proto libssh2_userauth_list
2042 + * List authentication methods
2043 + * Will yield successful login if "none" happens to be allowable for this user
2044 + * Not a common configuration for any SSH server though
2045 + * username should be NULL, or a null terminated string
2048 +libssh2_userauth_list(LIBSSH2_SESSION * session, const char *username,
2049 + unsigned int username_len)
2051 + static const unsigned char reply_codes[3] =
2052 + { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 };
2053 + /* packet_type(1) + username_len(4) + service_len(4) +
2054 + service(14)"ssh-connection" + method_len(4) + method(4)"none" */
2055 + unsigned long methods_len;
2059 + if (session->userauth_list_state == libssh2_NB_state_idle) {
2060 + /* Zero the whole thing out */
2061 + memset(&session->userauth_list_packet_requirev_state, 0,
2062 + sizeof(session->userauth_list_packet_requirev_state));
2064 + session->userauth_list_data_len = username_len + 31;
2066 + s = session->userauth_list_data =
2067 + LIBSSH2_ALLOC(session, session->userauth_list_data_len);
2068 + if (!session->userauth_list_data) {
2069 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
2070 + "Unable to allocate memory for userauth_list", 0);
2074 + *(s++) = SSH_MSG_USERAUTH_REQUEST;
2075 + libssh2_htonu32(s, username_len);
2078 + memcpy(s, username, username_len);
2079 + s += username_len;
2082 + libssh2_htonu32(s, 14);
2084 + memcpy(s, "ssh-connection", 14);
2087 + libssh2_htonu32(s, 4);
2089 + memcpy(s, "none", 4);
2092 + session->userauth_list_state = libssh2_NB_state_created;
2095 + if (session->userauth_list_state == libssh2_NB_state_created) {
2096 + rc = libssh2_packet_write(session, session->userauth_list_data,
2097 + session->userauth_list_data_len);
2098 + if (rc == PACKET_EAGAIN) {
2099 + libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
2100 + "Would block requesting userauth list", 0);
2103 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
2104 + "Unable to send userauth-none request", 0);
2105 + LIBSSH2_FREE(session, session->userauth_list_data);
2106 + session->userauth_list_data = NULL;
2107 + session->userauth_list_state = libssh2_NB_state_idle;
2110 + LIBSSH2_FREE(session, session->userauth_list_data);
2111 + session->userauth_list_data = NULL;
2113 + session->userauth_list_state = libssh2_NB_state_sent;
2116 + if (session->userauth_list_state == libssh2_NB_state_sent) {
2117 + rc = libssh2_packet_requirev_ex(session, reply_codes,
2118 + &session->userauth_list_data,
2119 + &session->userauth_list_data_len, 0,
2122 + userauth_list_packet_requirev_state);
2123 + if (rc == PACKET_EAGAIN) {
2124 + libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
2125 + "Would block requesting userauth list", 0);
2128 + libssh2_error(session, LIBSSH2_ERROR_NONE, "No error", 0);
2129 + session->userauth_list_state = libssh2_NB_state_idle;
2133 + if (session->userauth_list_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
2134 + /* Wow, who'dve thought... */
2135 + libssh2_error(session, LIBSSH2_ERROR_NONE, "No error", 0);
2136 + LIBSSH2_FREE(session, session->userauth_list_data);
2137 + session->userauth_list_data = NULL;
2138 + session->state |= LIBSSH2_STATE_AUTHENTICATED;
2139 + session->userauth_list_state = libssh2_NB_state_idle;
2143 + methods_len = libssh2_ntohu32(session->userauth_list_data + 1);
2145 + /* Do note that the memory areas overlap! */
2146 + memmove(session->userauth_list_data, session->userauth_list_data + 5,
2148 + session->userauth_list_data[methods_len] = '\0';
2149 + _libssh2_debug(session, LIBSSH2_DBG_AUTH, "Permitted auth methods: %s",
2150 + session->userauth_list_data);
2153 + session->userauth_list_state = libssh2_NB_state_idle;
2154 + return (char *) session->userauth_list_data;
2159 +/* {{{ libssh2_userauth_authenticated
2160 + * 0 if not yet authenticated
2161 + * non-zero is already authenticated
2164 +libssh2_userauth_authenticated(LIBSSH2_SESSION * session)
2166 + return session->state & LIBSSH2_STATE_AUTHENTICATED;
2171 +/* {{{ libssh2_userauth_password
2175 +libssh2_userauth_password_ex(LIBSSH2_SESSION * session, const char *username,
2176 + unsigned int username_len, const char *password,
2177 + unsigned int password_len,
2178 + LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb)))
2181 + static const unsigned char reply_codes[4] =
2182 + { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE,
2183 + SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, 0
2187 + if (session->userauth_pswd_state == libssh2_NB_state_idle) {
2188 + /* Zero the whole thing out */
2189 + memset(&session->userauth_pswd_packet_requirev_state, 0,
2190 + sizeof(session->userauth_pswd_packet_requirev_state));
2193 + * 40 = acket_type(1) + username_len(4) + service_len(4) +
2194 + * service(14)"ssh-connection" + method_len(4) + method(8)"password" +
2195 + * chgpwdbool(1) + password_len(4) */
2196 + session->userauth_pswd_data_len = username_len + password_len + 40;
2198 + session->userauth_pswd_data0 = ~SSH_MSG_USERAUTH_PASSWD_CHANGEREQ;
2200 + s = session->userauth_pswd_data =
2201 + LIBSSH2_ALLOC(session, session->userauth_pswd_data_len);
2202 + if (!session->userauth_pswd_data) {
2203 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
2204 + "Unable to allocate memory for userauth-password request",
2209 + *(s++) = SSH_MSG_USERAUTH_REQUEST;
2210 + libssh2_htonu32(s, username_len);
2212 + memcpy(s, username, username_len);
2213 + s += username_len;
2215 + libssh2_htonu32(s, sizeof("ssh-connection") - 1);
2217 + memcpy(s, "ssh-connection", sizeof("ssh-connection") - 1);
2218 + s += sizeof("ssh-connection") - 1;
2220 + libssh2_htonu32(s, sizeof("password") - 1);
2222 + memcpy(s, "password", sizeof("password") - 1);
2223 + s += sizeof("password") - 1;
2228 + libssh2_htonu32(s, password_len);
2230 + memcpy(s, password, password_len);
2231 + s += password_len;
2233 + _libssh2_debug(session, LIBSSH2_DBG_AUTH,
2234 + "Attempting to login using password authentication");
2236 + session->userauth_pswd_state = libssh2_NB_state_created;
2239 + if (session->userauth_pswd_state == libssh2_NB_state_created) {
2240 + rc = libssh2_packet_write(session, session->userauth_pswd_data,
2241 + session->userauth_pswd_data_len);
2242 + if (rc == PACKET_EAGAIN) {
2243 + return PACKET_EAGAIN;
2245 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
2246 + "Unable to send userauth-password request", 0);
2247 + LIBSSH2_FREE(session, session->userauth_pswd_data);
2248 + session->userauth_pswd_data = NULL;
2249 + session->userauth_pswd_state = libssh2_NB_state_idle;
2252 + LIBSSH2_FREE(session, session->userauth_pswd_data);
2253 + session->userauth_pswd_data = NULL;
2255 + session->userauth_pswd_state = libssh2_NB_state_sent;
2258 + password_response:
2260 + if ((session->userauth_pswd_state == libssh2_NB_state_sent)
2261 + || (session->userauth_pswd_state == libssh2_NB_state_sent1)
2262 + || (session->userauth_pswd_state == libssh2_NB_state_sent2)) {
2263 + if (session->userauth_pswd_state == libssh2_NB_state_sent) {
2264 + rc = libssh2_packet_requirev_ex(session, reply_codes,
2265 + &session->userauth_pswd_data,
2266 + &session->userauth_pswd_data_len,
2269 + userauth_pswd_packet_requirev_state);
2270 + if (rc == PACKET_EAGAIN) {
2271 + return PACKET_EAGAIN;
2273 + session->userauth_pswd_state = libssh2_NB_state_idle;
2277 + if (session->userauth_pswd_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
2278 + _libssh2_debug(session, LIBSSH2_DBG_AUTH,
2279 + "Password authentication successful");
2280 + LIBSSH2_FREE(session, session->userauth_pswd_data);
2281 + session->userauth_pswd_data = NULL;
2282 + session->state |= LIBSSH2_STATE_AUTHENTICATED;
2283 + session->userauth_pswd_state = libssh2_NB_state_idle;
2287 + session->userauth_pswd_newpw = NULL;
2288 + session->userauth_pswd_newpw_len = 0;
2290 + session->userauth_pswd_state = libssh2_NB_state_sent1;
2293 + if ((session->userauth_pswd_data[0] ==
2294 + SSH_MSG_USERAUTH_PASSWD_CHANGEREQ)
2295 + || (session->userauth_pswd_data0 ==
2296 + SSH_MSG_USERAUTH_PASSWD_CHANGEREQ)) {
2297 + session->userauth_pswd_data0 = SSH_MSG_USERAUTH_PASSWD_CHANGEREQ;
2299 + if ((session->userauth_pswd_state == libssh2_NB_state_sent1) ||
2300 + (session->userauth_pswd_state == libssh2_NB_state_sent2)) {
2301 + if (session->userauth_pswd_state == libssh2_NB_state_sent1) {
2302 + _libssh2_debug(session, LIBSSH2_DBG_AUTH,
2303 + "Password change required");
2304 + LIBSSH2_FREE(session, session->userauth_pswd_data);
2305 + session->userauth_pswd_data = NULL;
2307 + if (passwd_change_cb) {
2308 + if (session->userauth_pswd_state == libssh2_NB_state_sent1) {
2309 + passwd_change_cb(session,
2310 + &session->userauth_pswd_newpw,
2311 + &session->userauth_pswd_newpw_len,
2312 + &session->abstract);
2313 + if (!session->userauth_pswd_newpw) {
2314 + libssh2_error(session,
2315 + LIBSSH2_ERROR_PASSWORD_EXPIRED,
2316 + "Password expired, and callback failed",
2321 + /* basic data_len + newpw_len(4) */
2322 + session->userauth_pswd_data_len =
2323 + username_len + password_len + 44 +
2324 + session->userauth_pswd_newpw_len;
2326 + s = session->userauth_pswd_data =
2327 + LIBSSH2_ALLOC(session,
2328 + session->userauth_pswd_data_len);
2329 + if (!session->userauth_pswd_data) {
2330 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
2331 + "Unable to allocate memory for userauth-password-change request",
2333 + LIBSSH2_FREE(session,
2334 + session->userauth_pswd_newpw);
2335 + session->userauth_pswd_newpw = NULL;
2339 + *(s++) = SSH_MSG_USERAUTH_REQUEST;
2340 + libssh2_htonu32(s, username_len);
2342 + memcpy(s, username, username_len);
2343 + s += username_len;
2345 + libssh2_htonu32(s, sizeof("ssh-connection") - 1);
2347 + memcpy(s, "ssh-connection",
2348 + sizeof("ssh-connection") - 1);
2349 + s += sizeof("ssh-connection") - 1;
2351 + libssh2_htonu32(s, sizeof("password") - 1);
2353 + memcpy(s, "password", sizeof("password") - 1);
2354 + s += sizeof("password") - 1;
2359 + libssh2_htonu32(s, password_len);
2361 + memcpy(s, password, password_len);
2362 + s += password_len;
2364 + libssh2_htonu32(s, session->userauth_pswd_newpw_len);
2366 + memcpy(s, session->userauth_pswd_newpw,
2367 + session->userauth_pswd_newpw_len);
2368 + s += session->userauth_pswd_newpw_len;
2370 + session->userauth_pswd_state = libssh2_NB_state_sent2;
2373 + if (session->userauth_pswd_state == libssh2_NB_state_sent2) {
2374 + rc = libssh2_packet_write(session,
2375 + session->userauth_pswd_data,
2377 + userauth_pswd_data_len);
2378 + if (rc == PACKET_EAGAIN) {
2379 + return PACKET_EAGAIN;
2381 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
2382 + "Unable to send userauth-password-change request",
2384 + LIBSSH2_FREE(session, session->userauth_pswd_data);
2385 + session->userauth_pswd_data = NULL;
2386 + LIBSSH2_FREE(session,
2387 + session->userauth_pswd_newpw);
2388 + session->userauth_pswd_newpw = NULL;
2391 + LIBSSH2_FREE(session, session->userauth_pswd_data);
2392 + session->userauth_pswd_data = NULL;
2393 + LIBSSH2_FREE(session, session->userauth_pswd_newpw);
2394 + session->userauth_pswd_newpw = NULL;
2397 + * Ugliest use of goto ever. Blame it on the
2398 + * askN => requirev migration.
2400 + session->userauth_pswd_state = libssh2_NB_state_sent;
2401 + goto password_response;
2405 + libssh2_error(session, LIBSSH2_ERROR_PASSWORD_EXPIRED,
2406 + "Password Expired, and no callback specified",
2408 + session->userauth_pswd_state = libssh2_NB_state_idle;
2415 + LIBSSH2_FREE(session, session->userauth_pswd_data);
2416 + session->userauth_pswd_data = NULL;
2417 + session->userauth_pswd_state = libssh2_NB_state_idle;
2423 +/* {{{ libssh2_file_read_publickey
2424 + * Read a public key from an id_???.pub style file
2427 +libssh2_file_read_publickey(LIBSSH2_SESSION * session, unsigned char **method,
2428 + unsigned long *method_len,
2429 + unsigned char **pubkeydata,
2430 + unsigned long *pubkeydata_len,
2431 + const char *pubkeyfile)
2435 + unsigned char *pubkey = NULL, *sp1, *sp2, *tmp;
2436 + size_t pubkey_len = 0;
2437 + unsigned int tmp_len;
2439 + _libssh2_debug(session, LIBSSH2_DBG_AUTH, "Loading public key file: %s",
2441 + /* Read Public Key */
2442 + fd = fopen(pubkeyfile, "r");
2444 + libssh2_error(session, LIBSSH2_ERROR_FILE,
2445 + "Unable to open public key file", 0);
2448 + while (!feof(fd) && (c = fgetc(fd)) != '\r' && c != '\n')
2451 + /* the last character was EOF */
2456 + if (pubkey_len <= 1) {
2457 + libssh2_error(session, LIBSSH2_ERROR_FILE,
2458 + "Invalid data in public key file", 0);
2463 + pubkey = LIBSSH2_ALLOC(session, pubkey_len);
2465 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
2466 + "Unable to allocate memory for public key data", 0);
2470 + if (fread(pubkey, 1, pubkey_len, fd) != pubkey_len) {
2471 + libssh2_error(session, LIBSSH2_ERROR_FILE,
2472 + "Unable to read public key from file", 0);
2473 + LIBSSH2_FREE(session, pubkey);
2479 + * Remove trailing whitespace
2481 + while (pubkey_len && isspace(pubkey[pubkey_len - 1]))
2484 + if (!pubkey_len) {
2485 + libssh2_error(session, LIBSSH2_ERROR_FILE, "Missing public key data",
2487 + LIBSSH2_FREE(session, pubkey);
2491 + if ((sp1 = memchr(pubkey, ' ', pubkey_len)) == NULL) {
2492 + libssh2_error(session, LIBSSH2_ERROR_FILE, "Invalid public key data",
2494 + LIBSSH2_FREE(session, pubkey);
2497 + /* Wasting some bytes here (okay, more than some),
2498 + * but since it's likely to be freed soon anyway,
2499 + * we'll just avoid the extra free/alloc and call it a wash */
2501 + *method_len = sp1 - pubkey;
2505 + if ((sp2 = memchr(sp1, ' ', pubkey_len - *method_len)) == NULL) {
2506 + /* Assume that the id string is missing, but that it's okay */
2507 + sp2 = pubkey + pubkey_len;
2510 + if (libssh2_base64_decode
2511 + (session, (char **) &tmp, &tmp_len, (char *) sp1, sp2 - sp1)) {
2512 + libssh2_error(session, LIBSSH2_ERROR_FILE,
2513 + "Invalid key data, not base64 encoded", 0);
2514 + LIBSSH2_FREE(session, pubkey);
2517 + *pubkeydata = tmp;
2518 + *pubkeydata_len = tmp_len;
2525 +/* {{{ libssh2_file_read_privatekey
2526 + * Read a PEM encoded private key from an id_??? style file
2529 +libssh2_file_read_privatekey(LIBSSH2_SESSION * session,
2530 + const LIBSSH2_HOSTKEY_METHOD ** hostkey_method,
2531 + void **hostkey_abstract,
2532 + const unsigned char *method, int method_len,
2533 + const char *privkeyfile, const char *passphrase)
2535 + const LIBSSH2_HOSTKEY_METHOD **hostkey_methods_avail =
2536 + libssh2_hostkey_methods();
2538 + _libssh2_debug(session, LIBSSH2_DBG_AUTH, "Loading private key file: %s",
2540 + *hostkey_method = NULL;
2541 + *hostkey_abstract = NULL;
2542 + while (*hostkey_methods_avail && (*hostkey_methods_avail)->name) {
2543 + if ((*hostkey_methods_avail)->initPEM
2544 + && strncmp((*hostkey_methods_avail)->name, (const char *) method,
2545 + method_len) == 0) {
2546 + *hostkey_method = *hostkey_methods_avail;
2549 + hostkey_methods_avail++;
2551 + if (!*hostkey_method) {
2552 + libssh2_error(session, LIBSSH2_ERROR_METHOD_NONE,
2553 + "No handler for specified private key", 0);
2557 + if ((*hostkey_method)->
2558 + initPEM(session, privkeyfile, (unsigned char *) passphrase,
2559 + hostkey_abstract)) {
2560 + libssh2_error(session, LIBSSH2_ERROR_FILE,
2561 + "Unable to initialize private key from file", 0);
2570 +/* {{{ libssh2_userauth_hostbased_fromfile_ex
2571 + * Authenticate using a keypair found in the named files
2574 +libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION * session,
2575 + const char *username,
2576 + unsigned int username_len,
2577 + const char *publickey,
2578 + const char *privatekey,
2579 + const char *passphrase,
2580 + const char *hostname,
2581 + unsigned int hostname_len,
2582 + const char *local_username,
2583 + unsigned int local_username_len)
2585 + static const unsigned char reply_codes[3] =
2586 + { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 };
2589 + if (session->userauth_host_state == libssh2_NB_state_idle) {
2590 + const LIBSSH2_HOSTKEY_METHOD *privkeyobj;
2591 + unsigned char *pubkeydata, *sig;
2592 + unsigned long pubkeydata_len;
2593 + unsigned long sig_len;
2595 + unsigned char buf[5];
2596 + struct iovec datavec[4];
2598 + /* Zero the whole thing out */
2599 + memset(&session->userauth_host_packet_requirev_state, 0,
2600 + sizeof(session->userauth_host_packet_requirev_state));
2602 + if (libssh2_file_read_publickey
2603 + (session, &session->userauth_host_method,
2604 + &session->userauth_host_method_len, &pubkeydata, &pubkeydata_len,
2610 + * 48 = packet_type(1) + username_len(4) + servicename_len(4) +
2611 + * service_name(14)"ssh-connection" + authmethod_len(4) +
2612 + * authmethod(9)"hostbased" + method_len(4) + pubkeydata_len(4) +
2613 + * local_username_len(4)
2615 + session->userauth_host_packet_len =
2616 + username_len + session->userauth_host_method_len + hostname_len +
2617 + local_username_len + pubkeydata_len + 48;
2620 + * Preallocate space for an overall length, method name again,
2621 + * and the signature, which won't be any larger than the size of
2622 + * the publickeydata itself
2624 + session->userauth_host_s = session->userauth_host_packet =
2625 + LIBSSH2_ALLOC(session,
2626 + session->userauth_host_packet_len + 4 + (4 +
2628 + userauth_host_method_len)
2629 + + (4 + pubkeydata_len));
2630 + if (!session->userauth_host_packet) {
2631 + LIBSSH2_FREE(session, session->userauth_host_method);
2632 + session->userauth_host_method = NULL;
2636 + *(session->userauth_host_s++) = SSH_MSG_USERAUTH_REQUEST;
2637 + libssh2_htonu32(session->userauth_host_s, username_len);
2638 + session->userauth_host_s += 4;
2639 + memcpy(session->userauth_host_s, username, username_len);
2640 + session->userauth_host_s += username_len;
2642 + libssh2_htonu32(session->userauth_host_s, 14);
2643 + session->userauth_host_s += 4;
2644 + memcpy(session->userauth_host_s, "ssh-connection", 14);
2645 + session->userauth_host_s += 14;
2647 + libssh2_htonu32(session->userauth_host_s, 9);
2648 + session->userauth_host_s += 4;
2649 + memcpy(session->userauth_host_s, "hostbased", 9);
2650 + session->userauth_host_s += 9;
2652 + libssh2_htonu32(session->userauth_host_s,
2653 + session->userauth_host_method_len);
2654 + session->userauth_host_s += 4;
2655 + memcpy(session->userauth_host_s, session->userauth_host_method,
2656 + session->userauth_host_method_len);
2657 + session->userauth_host_s += session->userauth_host_method_len;
2659 + libssh2_htonu32(session->userauth_host_s, pubkeydata_len);
2660 + session->userauth_host_s += 4;
2661 + memcpy(session->userauth_host_s, pubkeydata, pubkeydata_len);
2662 + session->userauth_host_s += pubkeydata_len;
2664 + libssh2_htonu32(session->userauth_host_s, hostname_len);
2665 + session->userauth_host_s += 4;
2666 + memcpy(session->userauth_host_s, hostname, hostname_len);
2667 + session->userauth_host_s += hostname_len;
2669 + libssh2_htonu32(session->userauth_host_s, local_username_len);
2670 + session->userauth_host_s += 4;
2671 + memcpy(session->userauth_host_s, local_username, local_username_len);
2672 + session->userauth_host_s += local_username_len;
2674 + if (libssh2_file_read_privatekey
2675 + (session, &privkeyobj, &abstract, session->userauth_host_method,
2676 + session->userauth_host_method_len, privatekey, passphrase)) {
2677 + LIBSSH2_FREE(session, session->userauth_host_method);
2678 + session->userauth_host_method = NULL;
2679 + LIBSSH2_FREE(session, session->userauth_host_packet);
2680 + session->userauth_host_packet = NULL;
2684 + libssh2_htonu32(buf, session->session_id_len);
2685 + datavec[0].iov_base = buf;
2686 + datavec[0].iov_len = 4;
2687 + datavec[1].iov_base = session->session_id;
2688 + datavec[1].iov_len = session->session_id_len;
2689 + datavec[2].iov_base = session->userauth_host_packet;
2690 + datavec[2].iov_len = session->userauth_host_packet_len;
2692 + if (privkeyobj->signv(session, &sig, &sig_len, 3, datavec, &abstract)) {
2693 + LIBSSH2_FREE(session, session->userauth_host_method);
2694 + session->userauth_host_method = NULL;
2695 + LIBSSH2_FREE(session, session->userauth_host_packet);
2696 + session->userauth_host_packet = NULL;
2697 + if (privkeyobj->dtor) {
2698 + privkeyobj->dtor(session, &abstract);
2703 + if (privkeyobj->dtor) {
2704 + privkeyobj->dtor(session, &abstract);
2707 + if (sig_len > pubkeydata_len) {
2708 + unsigned char *newpacket;
2709 + /* Should *NEVER* happen, but...well.. better safe than sorry */
2710 + newpacket = LIBSSH2_REALLOC(session, session->userauth_host_packet, session->userauth_host_packet_len + 4 + (4 + session->userauth_host_method_len) + (4 + sig_len)); /* PK sigblob */
2712 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
2713 + "Failed allocating additional space for userauth-hostbased packet",
2715 + LIBSSH2_FREE(session, sig);
2716 + LIBSSH2_FREE(session, session->userauth_host_packet);
2717 + session->userauth_host_packet = NULL;
2718 + LIBSSH2_FREE(session, session->userauth_host_method);
2719 + session->userauth_host_method = NULL;
2722 + session->userauth_host_packet = newpacket;
2725 + session->userauth_host_s =
2726 + session->userauth_host_packet + session->userauth_host_packet_len;
2728 + libssh2_htonu32(session->userauth_host_s,
2729 + 4 + session->userauth_host_method_len + 4 + sig_len);
2730 + session->userauth_host_s += 4;
2732 + libssh2_htonu32(session->userauth_host_s,
2733 + session->userauth_host_method_len);
2734 + session->userauth_host_s += 4;
2735 + memcpy(session->userauth_host_s, session->userauth_host_method,
2736 + session->userauth_host_method_len);
2737 + session->userauth_host_s += session->userauth_host_method_len;
2738 + LIBSSH2_FREE(session, session->userauth_host_method);
2739 + session->userauth_host_method = NULL;
2741 + libssh2_htonu32(session->userauth_host_s, sig_len);
2742 + session->userauth_host_s += 4;
2743 + memcpy(session->userauth_host_s, sig, sig_len);
2744 + session->userauth_host_s += sig_len;
2745 + LIBSSH2_FREE(session, sig);
2747 + _libssh2_debug(session, LIBSSH2_DBG_AUTH,
2748 + "Attempting hostbased authentication");
2750 + session->userauth_host_state = libssh2_NB_state_created;
2753 + if (session->userauth_host_state == libssh2_NB_state_created) {
2754 + rc = libssh2_packet_write(session, session->userauth_host_packet,
2755 + session->userauth_host_s -
2756 + session->userauth_host_packet);
2757 + if (rc == PACKET_EAGAIN) {
2758 + return PACKET_EAGAIN;
2760 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
2761 + "Unable to send userauth-hostbased request", 0);
2762 + LIBSSH2_FREE(session, session->userauth_host_packet);
2763 + session->userauth_host_packet = NULL;
2764 + session->userauth_host_state = libssh2_NB_state_idle;
2767 + LIBSSH2_FREE(session, session->userauth_host_packet);
2768 + session->userauth_host_packet = NULL;
2770 + session->userauth_host_state = libssh2_NB_state_sent;
2773 + if (session->userauth_host_state == libssh2_NB_state_sent) {
2774 + unsigned long data_len;
2775 + rc = libssh2_packet_requirev_ex(session, reply_codes,
2776 + &session->userauth_host_data,
2777 + &data_len, 0, NULL, 0,
2779 + userauth_host_packet_requirev_state);
2780 + if (rc == PACKET_EAGAIN) {
2781 + return PACKET_EAGAIN;
2783 + session->userauth_host_state = libssh2_NB_state_idle;
2787 + if (session->userauth_host_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
2788 + _libssh2_debug(session, LIBSSH2_DBG_AUTH,
2789 + "Hostbased authentication successful");
2790 + /* We are us and we've proved it. */
2791 + LIBSSH2_FREE(session, session->userauth_host_data);
2792 + session->userauth_host_data = NULL;
2793 + session->state |= LIBSSH2_STATE_AUTHENTICATED;
2794 + session->userauth_host_state = libssh2_NB_state_idle;
2799 + /* This public key is not allowed for this user on this server */
2800 + LIBSSH2_FREE(session, session->userauth_host_data);
2801 + session->userauth_host_data = NULL;
2802 + libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
2803 + "Invalid signature for supplied public key, or bad username/public key combination",
2805 + session->userauth_host_state = libssh2_NB_state_idle;
2811 +/* {{{ libssh2_userauth_publickey_fromfile_ex
2812 + * Authenticate using a keypair found in the named files
2815 +libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION * session,
2816 + const char *username,
2817 + unsigned int username_len,
2818 + const char *publickey,
2819 + const char *privatekey,
2820 + const char *passphrase)
2822 + unsigned long pubkeydata_len = 0;
2823 + unsigned char reply_codes[4] =
2824 + { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE,
2825 + SSH_MSG_USERAUTH_PK_OK, 0
2829 + if (session->userauth_pblc_state == libssh2_NB_state_idle) {
2830 + unsigned char *pubkeydata;
2832 + /* Zero the whole thing out */
2833 + memset(&session->userauth_pblc_packet_requirev_state, 0,
2834 + sizeof(session->userauth_pblc_packet_requirev_state));
2836 + if (libssh2_file_read_publickey
2837 + (session, &session->userauth_pblc_method,
2838 + &session->userauth_pblc_method_len, &pubkeydata, &pubkeydata_len,
2844 + * 45 = packet_type(1) + username_len(4) + servicename_len(4) +
2845 + * service_name(14)"ssh-connection" + authmethod_len(4) +
2846 + * authmethod(9)"publickey" + sig_included(1)'\0' + algmethod_len(4) +
2847 + * publickey_len(4)
2849 + session->userauth_pblc_packet_len =
2850 + username_len + session->userauth_pblc_method_len + pubkeydata_len +
2854 + * Preallocate space for an overall length, method name again, and
2855 + * the signature, which won't be any larger than the size of the
2856 + * publickeydata itself
2858 + session->userauth_pblc_s = session->userauth_pblc_packet =
2859 + LIBSSH2_ALLOC(session,
2860 + session->userauth_pblc_packet_len + 4 + (4 +
2862 + userauth_pblc_method_len)
2863 + + (4 + pubkeydata_len));
2864 + if (!session->userauth_pblc_packet) {
2865 + LIBSSH2_FREE(session, session->userauth_pblc_method);
2866 + session->userauth_pblc_method = NULL;
2867 + LIBSSH2_FREE(session, pubkeydata);
2871 + *(session->userauth_pblc_s++) = SSH_MSG_USERAUTH_REQUEST;
2872 + libssh2_htonu32(session->userauth_pblc_s, username_len);
2873 + session->userauth_pblc_s += 4;
2874 + memcpy(session->userauth_pblc_s, username, username_len);
2875 + session->userauth_pblc_s += username_len;
2877 + libssh2_htonu32(session->userauth_pblc_s, 14);
2878 + session->userauth_pblc_s += 4;
2879 + memcpy(session->userauth_pblc_s, "ssh-connection", 14);
2880 + session->userauth_pblc_s += 14;
2882 + libssh2_htonu32(session->userauth_pblc_s, 9);
2883 + session->userauth_pblc_s += 4;
2884 + memcpy(session->userauth_pblc_s, "publickey", 9);
2885 + session->userauth_pblc_s += 9;
2887 + session->userauth_pblc_b = session->userauth_pblc_s;
2888 + /* Not sending signature with *this* packet */
2889 + *(session->userauth_pblc_s++) = 0;
2891 + libssh2_htonu32(session->userauth_pblc_s,
2892 + session->userauth_pblc_method_len);
2893 + session->userauth_pblc_s += 4;
2894 + memcpy(session->userauth_pblc_s, session->userauth_pblc_method,
2895 + session->userauth_pblc_method_len);
2896 + session->userauth_pblc_s += session->userauth_pblc_method_len;
2898 + libssh2_htonu32(session->userauth_pblc_s, pubkeydata_len);
2899 + session->userauth_pblc_s += 4;
2900 + memcpy(session->userauth_pblc_s, pubkeydata, pubkeydata_len);
2901 + session->userauth_pblc_s += pubkeydata_len;
2902 + LIBSSH2_FREE(session, pubkeydata);
2904 + _libssh2_debug(session, LIBSSH2_DBG_AUTH,
2905 + "Attempting publickey authentication");
2907 + session->userauth_pblc_state = libssh2_NB_state_created;
2910 + if (session->userauth_pblc_state == libssh2_NB_state_created) {
2911 + rc = libssh2_packet_write(session, session->userauth_pblc_packet,
2912 + session->userauth_pblc_packet_len);
2913 + if (rc == PACKET_EAGAIN) {
2914 + return PACKET_EAGAIN;
2916 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
2917 + "Unable to send userauth-publickey request", 0);
2918 + LIBSSH2_FREE(session, session->userauth_pblc_packet);
2919 + session->userauth_pblc_packet = NULL;
2920 + LIBSSH2_FREE(session, session->userauth_pblc_method);
2921 + session->userauth_pblc_method = NULL;
2922 + session->userauth_pblc_state = libssh2_NB_state_idle;
2926 + session->userauth_pblc_state = libssh2_NB_state_sent;
2929 + if (session->userauth_pblc_state == libssh2_NB_state_sent) {
2930 + const LIBSSH2_HOSTKEY_METHOD *privkeyobj;
2932 + unsigned char buf[5];
2933 + struct iovec datavec[4];
2934 + unsigned char *sig;
2935 + unsigned long sig_len;
2937 + rc = libssh2_packet_requirev_ex(session, reply_codes,
2938 + &session->userauth_pblc_data,
2939 + &session->userauth_pblc_data_len, 0,
2942 + userauth_pblc_packet_requirev_state);
2943 + if (rc == PACKET_EAGAIN) {
2944 + return PACKET_EAGAIN;
2946 + LIBSSH2_FREE(session, session->userauth_pblc_packet);
2947 + session->userauth_pblc_packet = NULL;
2948 + LIBSSH2_FREE(session, session->userauth_pblc_method);
2949 + session->userauth_pblc_method = NULL;
2950 + session->userauth_pblc_state = libssh2_NB_state_idle;
2954 + if (session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
2955 + _libssh2_debug(session, LIBSSH2_DBG_AUTH,
2956 + "Pubkey authentication prematurely successful");
2958 + * God help any SSH server that allows an UNVERIFIED
2959 + * public key to validate the user
2961 + LIBSSH2_FREE(session, session->userauth_pblc_data);
2962 + session->userauth_pblc_data = NULL;
2963 + LIBSSH2_FREE(session, session->userauth_pblc_packet);
2964 + session->userauth_pblc_packet = NULL;
2965 + LIBSSH2_FREE(session, session->userauth_pblc_method);
2966 + session->userauth_pblc_method = NULL;
2967 + session->state |= LIBSSH2_STATE_AUTHENTICATED;
2968 + session->userauth_pblc_state = libssh2_NB_state_idle;
2972 + if (session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_FAILURE) {
2973 + /* This public key is not allowed for this user on this server */
2974 + LIBSSH2_FREE(session, session->userauth_pblc_data);
2975 + session->userauth_pblc_data = NULL;
2976 + LIBSSH2_FREE(session, session->userauth_pblc_packet);
2977 + session->userauth_pblc_packet = NULL;
2978 + LIBSSH2_FREE(session, session->userauth_pblc_method);
2979 + session->userauth_pblc_method = NULL;
2980 + libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED,
2981 + "Username/PublicKey combination invalid", 0);
2982 + session->userauth_pblc_state = libssh2_NB_state_idle;
2986 + /* Semi-Success! */
2987 + LIBSSH2_FREE(session, session->userauth_pblc_data);
2988 + session->userauth_pblc_data = NULL;
2990 + if (libssh2_file_read_privatekey
2991 + (session, &privkeyobj, &abstract, session->userauth_pblc_method,
2992 + session->userauth_pblc_method_len, privatekey, passphrase)) {
2993 + LIBSSH2_FREE(session, session->userauth_pblc_method);
2994 + session->userauth_pblc_method = NULL;
2995 + LIBSSH2_FREE(session, session->userauth_pblc_packet);
2996 + session->userauth_pblc_packet = NULL;
2997 + session->userauth_pblc_state = libssh2_NB_state_idle;
3001 + *session->userauth_pblc_b = 0x01;
3003 + libssh2_htonu32(buf, session->session_id_len);
3004 + datavec[0].iov_base = buf;
3005 + datavec[0].iov_len = 4;
3006 + datavec[1].iov_base = session->session_id;
3007 + datavec[1].iov_len = session->session_id_len;
3008 + datavec[2].iov_base = session->userauth_pblc_packet;
3009 + datavec[2].iov_len = session->userauth_pblc_packet_len;
3011 + if (privkeyobj->signv(session, &sig, &sig_len, 3, datavec, &abstract)) {
3012 + LIBSSH2_FREE(session, session->userauth_pblc_method);
3013 + session->userauth_pblc_method = NULL;
3014 + LIBSSH2_FREE(session, session->userauth_pblc_packet);
3015 + session->userauth_pblc_packet = NULL;
3016 + if (privkeyobj->dtor) {
3017 + privkeyobj->dtor(session, &abstract);
3019 + session->userauth_pblc_state = libssh2_NB_state_idle;
3023 + if (privkeyobj->dtor) {
3024 + privkeyobj->dtor(session, &abstract);
3028 + * If this function was restarted, pubkeydata_len might still be 0
3029 + * which will cause an unnecessary but harmless realloc here.
3031 + if (sig_len > pubkeydata_len) {
3032 + unsigned char *newpacket;
3033 + /* Should *NEVER* happen, but...well.. better safe than sorry */
3034 + newpacket = LIBSSH2_REALLOC(session, session->userauth_pblc_packet, session->userauth_pblc_packet_len + 4 + (4 + session->userauth_pblc_method_len) + (4 + sig_len)); /* PK sigblob */
3036 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
3037 + "Failed allocating additional space for userauth-publickey packet",
3039 + LIBSSH2_FREE(session, sig);
3040 + LIBSSH2_FREE(session, session->userauth_pblc_packet);
3041 + session->userauth_pblc_packet = NULL;
3042 + LIBSSH2_FREE(session, session->userauth_pblc_method);
3043 + session->userauth_pblc_method = NULL;
3044 + session->userauth_pblc_state = libssh2_NB_state_idle;
3047 + session->userauth_pblc_packet = newpacket;
3050 + session->userauth_pblc_s =
3051 + session->userauth_pblc_packet + session->userauth_pblc_packet_len;
3052 + session->userauth_pblc_b = NULL;
3054 + libssh2_htonu32(session->userauth_pblc_s,
3055 + 4 + session->userauth_pblc_method_len + 4 + sig_len);
3056 + session->userauth_pblc_s += 4;
3058 + libssh2_htonu32(session->userauth_pblc_s,
3059 + session->userauth_pblc_method_len);
3060 + session->userauth_pblc_s += 4;
3061 + memcpy(session->userauth_pblc_s, session->userauth_pblc_method,
3062 + session->userauth_pblc_method_len);
3063 + session->userauth_pblc_s += session->userauth_pblc_method_len;
3064 + LIBSSH2_FREE(session, session->userauth_pblc_method);
3065 + session->userauth_pblc_method = NULL;
3067 + libssh2_htonu32(session->userauth_pblc_s, sig_len);
3068 + session->userauth_pblc_s += 4;
3069 + memcpy(session->userauth_pblc_s, sig, sig_len);
3070 + session->userauth_pblc_s += sig_len;
3071 + LIBSSH2_FREE(session, sig);
3073 + _libssh2_debug(session, LIBSSH2_DBG_AUTH,
3074 + "Attempting publickey authentication -- phase 2");
3076 + session->userauth_pblc_state = libssh2_NB_state_sent1;
3079 + if (session->userauth_pblc_state == libssh2_NB_state_sent1) {
3080 + rc = libssh2_packet_write(session, session->userauth_pblc_packet,
3081 + session->userauth_pblc_s -
3082 + session->userauth_pblc_packet);
3083 + if (rc == PACKET_EAGAIN) {
3084 + return PACKET_EAGAIN;
3086 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
3087 + "Unable to send userauth-publickey request", 0);
3088 + LIBSSH2_FREE(session, session->userauth_pblc_packet);
3089 + session->userauth_pblc_packet = NULL;
3090 + session->userauth_pblc_state = libssh2_NB_state_idle;
3093 + LIBSSH2_FREE(session, session->userauth_pblc_packet);
3094 + session->userauth_pblc_packet = NULL;
3096 + session->userauth_pblc_state = libssh2_NB_state_sent2;
3099 + /* PK_OK is no longer valid */
3100 + reply_codes[2] = 0;
3102 + rc = libssh2_packet_requirev_ex(session, reply_codes,
3103 + &session->userauth_pblc_data,
3104 + &session->userauth_pblc_data_len, 0, NULL,
3107 + userauth_pblc_packet_requirev_state);
3108 + if (rc == PACKET_EAGAIN) {
3109 + return PACKET_EAGAIN;
3111 + session->userauth_pblc_state = libssh2_NB_state_idle;
3115 + if (session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
3116 + _libssh2_debug(session, LIBSSH2_DBG_AUTH,
3117 + "Publickey authentication successful");
3118 + /* We are us and we've proved it. */
3119 + LIBSSH2_FREE(session, session->userauth_pblc_data);
3120 + session->userauth_pblc_data = NULL;
3121 + session->state |= LIBSSH2_STATE_AUTHENTICATED;
3122 + session->userauth_pblc_state = libssh2_NB_state_idle;
3126 + /* This public key is not allowed for this user on this server */
3127 + LIBSSH2_FREE(session, session->userauth_pblc_data);
3128 + session->userauth_pblc_data = NULL;
3129 + libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
3130 + "Invalid signature for supplied public key, or bad username/public key combination",
3132 + session->userauth_pblc_state = libssh2_NB_state_idle;
3138 +/* {{{ libssh2_userauth_keyboard_interactive
3139 + * Authenticate using a challenge-response authentication
3142 +libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION * session,
3143 + const char *username,
3144 + unsigned int username_len,
3145 + LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC((*response_callback)))
3150 + static const unsigned char reply_codes[4] = { SSH_MSG_USERAUTH_SUCCESS,
3151 + SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_INFO_REQUEST, 0
3153 + unsigned int language_tag_len;
3156 + if (session->userauth_kybd_state == libssh2_NB_state_idle) {
3157 + session->userauth_kybd_auth_name = NULL;
3158 + session->userauth_kybd_auth_instruction = NULL;
3159 + session->userauth_kybd_num_prompts = 0;
3160 + session->userauth_kybd_auth_failure = 1;
3161 + session->userauth_kybd_prompts = NULL;
3162 + session->userauth_kybd_responses = NULL;
3164 + /* Zero the whole thing out */
3165 + memset(&session->userauth_kybd_packet_requirev_state, 0,
3166 + sizeof(session->userauth_kybd_packet_requirev_state));
3168 + session->userauth_kybd_packet_len = 1 /* byte SSH_MSG_USERAUTH_REQUEST */
3169 + + 4 + username_len /* string user name (ISO-10646 UTF-8, as defined in [RFC-3629]) */
3170 + + 4 + 14 /* string service name (US-ASCII) */
3171 + + 4 + 20 /* string "keyboard-interactive" (US-ASCII) */
3172 + + 4 + 0 /* string language tag (as defined in [RFC-3066]) */
3173 + + 4 + 0 /* string submethods (ISO-10646 UTF-8) */
3176 + session->userauth_kybd_data = s =
3177 + LIBSSH2_ALLOC(session, session->userauth_kybd_packet_len);
3179 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
3180 + "Unable to allocate memory for keyboard-interactive authentication",
3185 + *s++ = SSH_MSG_USERAUTH_REQUEST;
3188 + libssh2_htonu32(s, username_len);
3190 + memcpy(s, username, username_len);
3191 + s += username_len;
3193 + /* service name */
3194 + libssh2_htonu32(s, sizeof("ssh-connection") - 1);
3196 + memcpy(s, "ssh-connection", sizeof("ssh-connection") - 1);
3197 + s += sizeof("ssh-connection") - 1;
3199 + /* "keyboard-interactive" */
3200 + libssh2_htonu32(s, sizeof("keyboard-interactive") - 1);
3202 + memcpy(s, "keyboard-interactive", sizeof("keyboard-interactive") - 1);
3203 + s += sizeof("keyboard-interactive") - 1;
3205 + /* language tag */
3206 + libssh2_htonu32(s, 0);
3210 + libssh2_htonu32(s, 0);
3213 + _libssh2_debug(session, LIBSSH2_DBG_AUTH,
3214 + "Attempting keyboard-interactive authentication");
3216 + session->userauth_kybd_state = libssh2_NB_state_created;
3219 + if (session->userauth_kybd_state == libssh2_NB_state_created) {
3220 + rc = libssh2_packet_write(session, session->userauth_kybd_data,
3221 + session->userauth_kybd_packet_len);
3222 + if (rc == PACKET_EAGAIN) {
3223 + return PACKET_EAGAIN;
3225 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
3226 + "Unable to send keyboard-interactive request", 0);
3227 + LIBSSH2_FREE(session, session->userauth_kybd_data);
3228 + session->userauth_kybd_data = NULL;
3229 + session->userauth_kybd_state = libssh2_NB_state_idle;
3232 + LIBSSH2_FREE(session, session->userauth_kybd_data);
3233 + session->userauth_kybd_data = NULL;
3235 + session->userauth_kybd_state = libssh2_NB_state_sent;
3239 + if (session->userauth_kybd_state == libssh2_NB_state_sent) {
3240 + rc = libssh2_packet_requirev_ex(session, reply_codes,
3241 + &session->userauth_kybd_data,
3242 + &session->userauth_kybd_data_len,
3245 + userauth_kybd_packet_requirev_state);
3246 + if (rc == PACKET_EAGAIN) {
3247 + return PACKET_EAGAIN;
3249 + session->userauth_kybd_state = libssh2_NB_state_idle;
3253 + if (session->userauth_kybd_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
3254 + _libssh2_debug(session, LIBSSH2_DBG_AUTH,
3255 + "Keyboard-interactive authentication successful");
3256 + LIBSSH2_FREE(session, session->userauth_kybd_data);
3257 + session->userauth_kybd_data = NULL;
3258 + session->state |= LIBSSH2_STATE_AUTHENTICATED;
3259 + session->userauth_kybd_state = libssh2_NB_state_idle;
3263 + if (session->userauth_kybd_data[0] == SSH_MSG_USERAUTH_FAILURE) {
3264 + LIBSSH2_FREE(session, session->userauth_kybd_data);
3265 + session->userauth_kybd_data = NULL;
3266 + session->userauth_kybd_state = libssh2_NB_state_idle;
3270 + /* server requested PAM-like conversation */
3272 + s = session->userauth_kybd_data + 1;
3274 + /* string name (ISO-10646 UTF-8) */
3275 + session->userauth_kybd_auth_name_len = libssh2_ntohu32(s);
3277 + session->userauth_kybd_auth_name =
3278 + LIBSSH2_ALLOC(session, session->userauth_kybd_auth_name_len);
3279 + if (!session->userauth_kybd_auth_name) {
3280 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
3281 + "Unable to allocate memory for keyboard-interactive 'name' request field",
3285 + memcpy(session->userauth_kybd_auth_name, s,
3286 + session->userauth_kybd_auth_name_len);
3287 + s += session->userauth_kybd_auth_name_len;
3289 + /* string instruction (ISO-10646 UTF-8) */
3290 + session->userauth_kybd_auth_instruction_len = libssh2_ntohu32(s);
3292 + session->userauth_kybd_auth_instruction =
3293 + LIBSSH2_ALLOC(session,
3294 + session->userauth_kybd_auth_instruction_len);
3295 + if (!session->userauth_kybd_auth_instruction) {
3296 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
3297 + "Unable to allocate memory for keyboard-interactive 'instruction' request field",
3301 + memcpy(session->userauth_kybd_auth_instruction, s,
3302 + session->userauth_kybd_auth_instruction_len);
3303 + s += session->userauth_kybd_auth_instruction_len;
3305 + /* string language tag (as defined in [RFC-3066]) */
3306 + language_tag_len = libssh2_ntohu32(s);
3308 + /* ignoring this field as deprecated */
3309 + s += language_tag_len;
3311 + /* int num-prompts */
3312 + session->userauth_kybd_num_prompts = libssh2_ntohu32(s);
3315 + session->userauth_kybd_prompts =
3316 + LIBSSH2_ALLOC(session,
3317 + sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) *
3318 + session->userauth_kybd_num_prompts);
3319 + if (!session->userauth_kybd_prompts) {
3320 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
3321 + "Unable to allocate memory for keyboard-interactive prompts array",
3325 + memset(session->userauth_kybd_prompts, 0,
3326 + sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) *
3327 + session->userauth_kybd_num_prompts);
3329 + session->userauth_kybd_responses =
3330 + LIBSSH2_ALLOC(session,
3331 + sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) *
3332 + session->userauth_kybd_num_prompts);
3333 + if (!session->userauth_kybd_responses) {
3334 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
3335 + "Unable to allocate memory for keyboard-interactive responses array",
3339 + memset(session->userauth_kybd_responses, 0,
3340 + sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) *
3341 + session->userauth_kybd_num_prompts);
3343 + for(i = 0; i != session->userauth_kybd_num_prompts; ++i) {
3344 + /* string prompt[1] (ISO-10646 UTF-8) */
3345 + session->userauth_kybd_prompts[i].length = libssh2_ntohu32(s);
3347 + session->userauth_kybd_prompts[i].text =
3348 + LIBSSH2_ALLOC(session,
3349 + session->userauth_kybd_prompts[i].length);
3350 + if (!session->userauth_kybd_prompts[i].text) {
3351 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
3352 + "Unable to allocate memory for keyboard-interactive prompt message",
3356 + memcpy(session->userauth_kybd_prompts[i].text, s,
3357 + session->userauth_kybd_prompts[i].length);
3358 + s += session->userauth_kybd_prompts[i].length;
3360 + /* boolean echo[1] */
3361 + session->userauth_kybd_prompts[i].echo = *s++;
3364 + response_callback(session->userauth_kybd_auth_name,
3365 + session->userauth_kybd_auth_name_len,
3366 + session->userauth_kybd_auth_instruction,
3367 + session->userauth_kybd_auth_instruction_len,
3368 + session->userauth_kybd_num_prompts,
3369 + session->userauth_kybd_prompts,
3370 + session->userauth_kybd_responses,
3371 + &session->abstract);
3373 + _libssh2_debug(session, LIBSSH2_DBG_AUTH,
3374 + "Keyboard-interactive response callback function invoked");
3376 + session->userauth_kybd_packet_len = 1 /* byte SSH_MSG_USERAUTH_INFO_RESPONSE */
3377 + + 4 /* int num-responses */
3380 + for(i = 0; i != session->userauth_kybd_num_prompts; ++i) {
3381 + /* string response[1] (ISO-10646 UTF-8) */
3382 + session->userauth_kybd_packet_len +=
3383 + 4 + session->userauth_kybd_responses[i].length;
3386 + session->userauth_kybd_data = s =
3387 + LIBSSH2_ALLOC(session, session->userauth_kybd_packet_len);
3389 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
3390 + "Unable to allocate memory for keyboard-interactive response packet",
3395 + *s = SSH_MSG_USERAUTH_INFO_RESPONSE;
3397 + libssh2_htonu32(s, session->userauth_kybd_num_prompts);
3400 + for(i = 0; i != session->userauth_kybd_num_prompts; ++i) {
3401 + libssh2_htonu32(s, session->userauth_kybd_responses[i].length);
3403 + memcpy(s, session->userauth_kybd_responses[i].text,
3404 + session->userauth_kybd_responses[i].length);
3405 + s += session->userauth_kybd_responses[i].length;
3408 + session->userauth_kybd_state = libssh2_NB_state_sent1;
3411 + if (session->userauth_kybd_state == libssh2_NB_state_sent1) {
3412 + rc = libssh2_packet_write(session, session->userauth_kybd_data,
3413 + session->userauth_kybd_packet_len);
3414 + if (rc == PACKET_EAGAIN) {
3415 + return PACKET_EAGAIN;
3418 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
3419 + "Unable to send userauth-keyboard-interactive request",
3424 + session->userauth_kybd_auth_failure = 0;
3429 + * It's safe to clean all the data here, because unallocated pointers
3430 + * are filled by zeroes
3433 + LIBSSH2_FREE(session, session->userauth_kybd_data);
3434 + session->userauth_kybd_data = NULL;
3436 + if (session->userauth_kybd_prompts) {
3437 + for(i = 0; i != session->userauth_kybd_num_prompts; ++i) {
3438 + LIBSSH2_FREE(session, session->userauth_kybd_prompts[i].text);
3439 + session->userauth_kybd_prompts[i].text = NULL;
3443 + if (session->userauth_kybd_responses) {
3444 + for(i = 0; i != session->userauth_kybd_num_prompts; ++i) {
3445 + LIBSSH2_FREE(session,
3446 + session->userauth_kybd_responses[i].text);
3447 + session->userauth_kybd_responses[i].text = NULL;
3451 + LIBSSH2_FREE(session, session->userauth_kybd_prompts);
3452 + session->userauth_kybd_prompts = NULL;
3453 + LIBSSH2_FREE(session, session->userauth_kybd_responses);
3454 + session->userauth_kybd_responses = NULL;
3456 + if (session->userauth_kybd_auth_failure) {
3457 + session->userauth_kybd_state = libssh2_NB_state_idle;
3461 + session->userauth_kybd_state = libssh2_NB_state_sent;
3467 Property changes on: libssh2/src/userauth.c
3468 ___________________________________________________________________
3469 Added: svn:mime-type
3472 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
3473 Added: cvs2svn:cvs-rev
3475 Added: svn:eol-style
3478 Index: libssh2/src/mac.c
3479 ===================================================================
3480 --- libssh2/src/mac.c (.../tags/RELEASE_0_11_0)
3481 +++ libssh2/src/mac.c (.../trunk)
3483 +/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
3484 + * All rights reserved.
3486 + * Redistribution and use in source and binary forms,
3487 + * with or without modification, are permitted provided
3488 + * that the following conditions are met:
3490 + * Redistributions of source code must retain the above
3491 + * copyright notice, this list of conditions and the
3492 + * following disclaimer.
3494 + * Redistributions in binary form must reproduce the above
3495 + * copyright notice, this list of conditions and the following
3496 + * disclaimer in the documentation and/or other materials
3497 + * provided with the distribution.
3499 + * Neither the name of the copyright holder nor the names
3500 + * of any other contributors may be used to endorse or
3501 + * promote products derived from this software without
3502 + * specific prior written permission.
3504 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
3505 + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
3506 + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
3507 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3508 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
3509 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3510 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
3511 + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
3512 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
3513 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
3514 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
3515 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
3516 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
3520 +#include "libssh2_priv.h"
3522 +#ifdef LIBSSH2_MAC_NONE
3523 +/* {{{ libssh2_mac_none_MAC
3524 + * Minimalist MAC: No MAC
3527 +libssh2_mac_none_MAC(LIBSSH2_SESSION * session, unsigned char *buf,
3528 + unsigned long seqno, const unsigned char *packet,
3529 + unsigned long packet_len, const unsigned char *addtl,
3530 + unsigned long addtl_len, void **abstract)
3538 +static LIBSSH2_MAC_METHOD libssh2_mac_method_none = {
3543 + libssh2_mac_none_MAC,
3546 +#endif /* LIBSSH2_MAC_NONE */
3548 +/* {{{ libssh2_mac_method_common_init
3549 + * Initialize simple mac methods
3552 +libssh2_mac_method_common_init(LIBSSH2_SESSION * session, unsigned char *key,
3553 + int *free_key, void **abstract)
3564 +/* {{{ libssh2_mac_method_common_dtor
3565 + * Cleanup simple mac methods
3568 +libssh2_mac_method_common_dtor(LIBSSH2_SESSION * session, void **abstract)
3571 + LIBSSH2_FREE(session, *abstract);
3580 +/* {{{ libssh2_mac_method_hmac_sha1_hash
3581 + * Calculate hash using full sha1 value
3584 +libssh2_mac_method_hmac_sha1_hash(LIBSSH2_SESSION * session,
3585 + unsigned char *buf, unsigned long seqno,
3586 + const unsigned char *packet,
3587 + unsigned long packet_len,
3588 + const unsigned char *addtl,
3589 + unsigned long addtl_len, void **abstract)
3591 + libssh2_hmac_ctx ctx;
3592 + unsigned char seqno_buf[4];
3595 + libssh2_htonu32(seqno_buf, seqno);
3597 + libssh2_hmac_sha1_init(&ctx, *abstract, 20);
3598 + libssh2_hmac_update(ctx, seqno_buf, 4);
3599 + libssh2_hmac_update(ctx, packet, packet_len);
3600 + if (addtl && addtl_len) {
3601 + libssh2_hmac_update(ctx, addtl, addtl_len);
3603 + libssh2_hmac_final(ctx, buf);
3604 + libssh2_hmac_cleanup(&ctx);
3611 +static const LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_sha1 = {
3615 + libssh2_mac_method_common_init,
3616 + libssh2_mac_method_hmac_sha1_hash,
3617 + libssh2_mac_method_common_dtor,
3620 +/* {{{ libssh2_mac_method_hmac_sha1_96_hash
3621 + * Calculate hash using first 96 bits of sha1 value
3624 +libssh2_mac_method_hmac_sha1_96_hash(LIBSSH2_SESSION * session,
3625 + unsigned char *buf, unsigned long seqno,
3626 + const unsigned char *packet,
3627 + unsigned long packet_len,
3628 + const unsigned char *addtl,
3629 + unsigned long addtl_len, void **abstract)
3631 + unsigned char temp[SHA_DIGEST_LENGTH];
3633 + libssh2_mac_method_hmac_sha1_hash(session, temp, seqno, packet, packet_len,
3634 + addtl, addtl_len, abstract);
3635 + memcpy(buf, (char *) temp, 96 / 8);
3642 +static const LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_sha1_96 = {
3646 + libssh2_mac_method_common_init,
3647 + libssh2_mac_method_hmac_sha1_96_hash,
3648 + libssh2_mac_method_common_dtor,
3651 +/* {{{ libssh2_mac_method_hmac_md5_hash
3652 + * Calculate hash using full md5 value
3655 +libssh2_mac_method_hmac_md5_hash(LIBSSH2_SESSION * session, unsigned char *buf,
3656 + unsigned long seqno,
3657 + const unsigned char *packet,
3658 + unsigned long packet_len,
3659 + const unsigned char *addtl,
3660 + unsigned long addtl_len, void **abstract)
3662 + libssh2_hmac_ctx ctx;
3663 + unsigned char seqno_buf[4];
3666 + libssh2_htonu32(seqno_buf, seqno);
3668 + libssh2_hmac_md5_init(&ctx, *abstract, 16);
3669 + libssh2_hmac_update(ctx, seqno_buf, 4);
3670 + libssh2_hmac_update(ctx, packet, packet_len);
3671 + if (addtl && addtl_len) {
3672 + libssh2_hmac_update(ctx, addtl, addtl_len);
3674 + libssh2_hmac_final(ctx, buf);
3675 + libssh2_hmac_cleanup(&ctx);
3682 +static const LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_md5 = {
3686 + libssh2_mac_method_common_init,
3687 + libssh2_mac_method_hmac_md5_hash,
3688 + libssh2_mac_method_common_dtor,
3691 +/* {{{ libssh2_mac_method_hmac_md5_96_hash
3692 + * Calculate hash using first 96 bits of md5 value
3695 +libssh2_mac_method_hmac_md5_96_hash(LIBSSH2_SESSION * session,
3696 + unsigned char *buf, unsigned long seqno,
3697 + const unsigned char *packet,
3698 + unsigned long packet_len,
3699 + const unsigned char *addtl,
3700 + unsigned long addtl_len, void **abstract)
3702 + unsigned char temp[MD5_DIGEST_LENGTH];
3704 + libssh2_mac_method_hmac_md5_hash(session, temp, seqno, packet, packet_len,
3705 + addtl, addtl_len, abstract);
3706 + memcpy(buf, (char *) temp, 96 / 8);
3713 +static const LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_md5_96 = {
3717 + libssh2_mac_method_common_init,
3718 + libssh2_mac_method_hmac_md5_96_hash,
3719 + libssh2_mac_method_common_dtor,
3722 +#if LIBSSH2_HMAC_RIPEMD
3723 +/* {{{ libssh2_mac_method_hmac_ripemd160_hash
3724 + * Calculate hash using ripemd160 value
3727 +libssh2_mac_method_hmac_ripemd160_hash(LIBSSH2_SESSION * session,
3728 + unsigned char *buf, unsigned long seqno,
3729 + const unsigned char *packet,
3730 + unsigned long packet_len,
3731 + const unsigned char *addtl,
3732 + unsigned long addtl_len,
3735 + libssh2_hmac_ctx ctx;
3736 + unsigned char seqno_buf[4];
3739 + libssh2_htonu32(seqno_buf, seqno);
3741 + libssh2_hmac_ripemd160_init(&ctx, *abstract, 20);
3742 + libssh2_hmac_update(ctx, seqno_buf, 4);
3743 + libssh2_hmac_update(ctx, packet, packet_len);
3744 + if (addtl && addtl_len) {
3745 + libssh2_hmac_update(ctx, addtl, addtl_len);
3747 + libssh2_hmac_final(ctx, buf);
3748 + libssh2_hmac_cleanup(&ctx);
3755 +static const LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_ripemd160 = {
3759 + libssh2_mac_method_common_init,
3760 + libssh2_mac_method_hmac_ripemd160_hash,
3761 + libssh2_mac_method_common_dtor,
3764 +static const LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_ripemd160_openssh_com = {
3765 + "hmac-ripemd160@openssh.com",
3768 + libssh2_mac_method_common_init,
3769 + libssh2_mac_method_hmac_ripemd160_hash,
3770 + libssh2_mac_method_common_dtor,
3772 +#endif /* LIBSSH2_HMAC_RIPEMD */
3774 +static const LIBSSH2_MAC_METHOD *_libssh2_mac_methods[] = {
3775 + &libssh2_mac_method_hmac_sha1,
3776 + &libssh2_mac_method_hmac_sha1_96,
3777 + &libssh2_mac_method_hmac_md5,
3778 + &libssh2_mac_method_hmac_md5_96,
3779 +#if LIBSSH2_HMAC_RIPEMD
3780 + &libssh2_mac_method_hmac_ripemd160,
3781 + &libssh2_mac_method_hmac_ripemd160_openssh_com,
3782 +#endif /* LIBSSH2_HMAC_RIPEMD */
3783 +#ifdef LIBSSH2_MAC_NONE
3784 + &libssh2_mac_method_none,
3785 +#endif /* LIBSSH2_MAC_NONE */
3789 +const LIBSSH2_MAC_METHOD **
3790 +libssh2_mac_methods(void)
3792 + return _libssh2_mac_methods;
3795 Property changes on: libssh2/src/mac.c
3796 ___________________________________________________________________
3797 Added: svn:mime-type
3800 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
3801 Added: cvs2svn:cvs-rev
3803 Added: svn:eol-style
3806 Index: libssh2/src/crypt.c
3807 ===================================================================
3808 --- libssh2/src/crypt.c (.../tags/RELEASE_0_11_0)
3809 +++ libssh2/src/crypt.c (.../trunk)
3811 +/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
3812 + * All rights reserved.
3814 + * Redistribution and use in source and binary forms,
3815 + * with or without modification, are permitted provided
3816 + * that the following conditions are met:
3818 + * Redistributions of source code must retain the above
3819 + * copyright notice, this list of conditions and the
3820 + * following disclaimer.
3822 + * Redistributions in binary form must reproduce the above
3823 + * copyright notice, this list of conditions and the following
3824 + * disclaimer in the documentation and/or other materials
3825 + * provided with the distribution.
3827 + * Neither the name of the copyright holder nor the names
3828 + * of any other contributors may be used to endorse or
3829 + * promote products derived from this software without
3830 + * specific prior written permission.
3832 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
3833 + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
3834 + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
3835 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3836 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
3837 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3838 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
3839 + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
3840 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
3841 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
3842 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
3843 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
3844 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
3848 +#include "libssh2_priv.h"
3850 +#ifdef LIBSSH2_CRYPT_NONE
3851 +/* {{{ libssh2_crypt_none_crypt
3852 + * Minimalist cipher: VERY secure *wink*
3855 +libssh2_crypt_none_crypt(LIBSSH2_SESSION * session, unsigned char *buf,
3858 + /* Do nothing to the data! */
3864 +static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_none = {
3866 + 8, /* blocksize (SSH2 defines minimum blocksize as 8) */
3868 + 0, /* secret_len */
3871 + libssh2_crypt_none_crypt,
3874 +#endif /* LIBSSH2_CRYPT_NONE */
3879 + _libssh2_cipher_type(algo);
3880 + _libssh2_cipher_ctx h;
3884 +_libssh2_init(LIBSSH2_SESSION * session,
3885 + const LIBSSH2_CRYPT_METHOD * method,
3886 + unsigned char *iv, int *free_iv,
3887 + unsigned char *secret, int *free_secret,
3888 + int encrypt, void **abstract)
3890 + struct crypt_ctx *ctx = LIBSSH2_ALLOC(session,
3891 + sizeof(struct crypt_ctx));
3895 + ctx->encrypt = encrypt;
3896 + ctx->algo = method->algo;
3897 + if (_libssh2_cipher_init(&ctx->h, ctx->algo, iv, secret, encrypt)) {
3898 + LIBSSH2_FREE(session, ctx);
3908 +_libssh2_encrypt(LIBSSH2_SESSION * session, unsigned char *block,
3911 + struct crypt_ctx *cctx = *(struct crypt_ctx **) abstract;
3913 + return _libssh2_cipher_crypt(&cctx->h, cctx->algo, cctx->encrypt, block);
3917 +_libssh2_dtor(LIBSSH2_SESSION * session, void **abstract)
3919 + struct crypt_ctx **cctx = (struct crypt_ctx **) abstract;
3920 + if (cctx && *cctx) {
3921 + _libssh2_cipher_dtor(&(*cctx)->h);
3922 + LIBSSH2_FREE(session, *cctx);
3929 +static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes128_cbc = {
3931 + 16, /* blocksize */
3932 + 16, /* initial value length */
3933 + 16, /* secret length -- 16*8 == 128bit */
3936 + &_libssh2_encrypt,
3938 + _libssh2_cipher_aes128
3941 +static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes192_cbc = {
3943 + 16, /* blocksize */
3944 + 16, /* initial value length */
3945 + 24, /* secret length -- 24*8 == 192bit */
3948 + &_libssh2_encrypt,
3950 + _libssh2_cipher_aes192
3953 +static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes256_cbc = {
3955 + 16, /* blocksize */
3956 + 16, /* initial value length */
3957 + 32, /* secret length -- 32*8 == 256bit */
3960 + &_libssh2_encrypt,
3962 + _libssh2_cipher_aes256
3965 +/* rijndael-cbc@lysator.liu.se == aes256-cbc */
3966 +static const LIBSSH2_CRYPT_METHOD
3967 + libssh2_crypt_method_rijndael_cbc_lysator_liu_se = {
3968 + "rijndael-cbc@lysator.liu.se",
3969 + 16, /* blocksize */
3970 + 16, /* initial value length */
3971 + 32, /* secret length -- 32*8 == 256bit */
3974 + &_libssh2_encrypt,
3976 + _libssh2_cipher_aes256
3978 +#endif /* LIBSSH2_AES */
3980 +#if LIBSSH2_BLOWFISH
3981 +static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_blowfish_cbc = {
3983 + 8, /* blocksize */
3984 + 8, /* initial value length */
3985 + 16, /* secret length */
3988 + &_libssh2_encrypt,
3990 + _libssh2_cipher_blowfish
3992 +#endif /* LIBSSH2_BLOWFISH */
3995 +static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_arcfour = {
3997 + 8, /* blocksize */
3998 + 8, /* initial value length */
3999 + 16, /* secret length */
4002 + &_libssh2_encrypt,
4004 + _libssh2_cipher_arcfour
4006 +#endif /* LIBSSH2_RC4 */
4009 +static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_cast128_cbc = {
4011 + 8, /* blocksize */
4012 + 8, /* initial value length */
4013 + 16, /* secret length */
4016 + &_libssh2_encrypt,
4018 + _libssh2_cipher_cast5
4020 +#endif /* LIBSSH2_CAST */
4023 +static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_3des_cbc = {
4025 + 8, /* blocksize */
4026 + 8, /* initial value length */
4027 + 24, /* secret length */
4030 + &_libssh2_encrypt,
4032 + _libssh2_cipher_3des
4036 +static const LIBSSH2_CRYPT_METHOD *_libssh2_crypt_methods[] = {
4038 + &libssh2_crypt_method_aes256_cbc,
4039 + &libssh2_crypt_method_rijndael_cbc_lysator_liu_se, /* == aes256-cbc */
4040 + &libssh2_crypt_method_aes192_cbc,
4041 + &libssh2_crypt_method_aes128_cbc,
4042 +#endif /* LIBSSH2_AES */
4043 +#if LIBSSH2_BLOWFISH
4044 + &libssh2_crypt_method_blowfish_cbc,
4045 +#endif /* LIBSSH2_BLOWFISH */
4047 + &libssh2_crypt_method_arcfour,
4048 +#endif /* LIBSSH2_RC4 */
4050 + &libssh2_crypt_method_cast128_cbc,
4051 +#endif /* LIBSSH2_CAST */
4053 + &libssh2_crypt_method_3des_cbc,
4054 +#endif /* LIBSSH2_DES */
4055 +#ifdef LIBSSH2_CRYPT_NONE
4056 + &libssh2_crypt_method_none,
4061 +/* Expose to kex.c */
4062 +const LIBSSH2_CRYPT_METHOD **
4063 +libssh2_crypt_methods(void)
4065 + return _libssh2_crypt_methods;
4068 Property changes on: libssh2/src/crypt.c
4069 ___________________________________________________________________
4070 Added: svn:mime-type
4073 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
4074 Added: cvs2svn:cvs-rev
4076 Added: svn:eol-style
4079 Index: libssh2/src/libgcrypt.h
4080 ===================================================================
4081 --- libssh2/src/libgcrypt.h (.../tags/RELEASE_0_11_0)
4082 +++ libssh2/src/libgcrypt.h (.../trunk)
4084 +/* Copyright (C) 2006, 2007, The Written Word, Inc.
4085 + * Copyright (C) 2008, Simon Josefsson
4086 + * All rights reserved.
4088 + * Redistribution and use in source and binary forms,
4089 + * with or without modification, are permitted provided
4090 + * that the following conditions are met:
4092 + * Redistributions of source code must retain the above
4093 + * copyright notice, this list of conditions and the
4094 + * following disclaimer.
4096 + * Redistributions in binary form must reproduce the above
4097 + * copyright notice, this list of conditions and the following
4098 + * disclaimer in the documentation and/or other materials
4099 + * provided with the distribution.
4101 + * Neither the name of the copyright holder nor the names
4102 + * of any other contributors may be used to endorse or
4103 + * promote products derived from this software without
4104 + * specific prior written permission.
4106 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
4107 + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
4108 + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
4109 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4110 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
4111 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4112 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
4113 + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
4114 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
4115 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
4116 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
4117 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
4118 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
4122 +#include <gcrypt.h>
4124 +#define LIBSSH2_MD5 1
4126 +#define LIBSSH2_HMAC_RIPEMD 1
4128 +#define LIBSSH2_AES 1
4129 +#define LIBSSH2_BLOWFISH 1
4130 +#define LIBSSH2_RC4 1
4131 +#define LIBSSH2_CAST 1
4132 +#define LIBSSH2_3DES 1
4134 +#define LIBSSH2_RSA 1
4135 +#define LIBSSH2_DSA 1
4137 +#define MD5_DIGEST_LENGTH 16
4138 +#define SHA_DIGEST_LENGTH 20
4140 +#define libssh2_random(buf, len) \
4141 + (gcry_randomize ((buf), (len), GCRY_STRONG_RANDOM), 1)
4143 +#define libssh2_sha1_ctx gcry_md_hd_t
4144 +#define libssh2_sha1_init(ctx) gcry_md_open (ctx, GCRY_MD_SHA1, 0);
4145 +#define libssh2_sha1_update(ctx, data, len) gcry_md_write (ctx, data, len)
4146 +#define libssh2_sha1_final(ctx, out) \
4147 + memcpy (out, gcry_md_read (ctx, 0), 20), gcry_md_close (ctx)
4148 +#define libssh2_sha1(message, len, out) \
4149 + gcry_md_hash_buffer (GCRY_MD_SHA1, out, message, len)
4151 +#define libssh2_md5_ctx gcry_md_hd_t
4152 +#define libssh2_md5_init(ctx) gcry_md_open (ctx, GCRY_MD_MD5, 0);
4153 +#define libssh2_md5_update(ctx, data, len) gcry_md_write (ctx, data, len)
4154 +#define libssh2_md5_final(ctx, out) \
4155 + memcpy (out, gcry_md_read (ctx, 0), 20), gcry_md_close (ctx)
4156 +#define libssh2_md5(message, len, out) \
4157 + gcry_md_hash_buffer (GCRY_MD_MD5, out, message, len)
4159 +#define libssh2_hmac_ctx gcry_md_hd_t
4160 +#define libssh2_hmac_sha1_init(ctx, key, keylen) \
4161 + gcry_md_open (ctx, GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC), \
4162 + gcry_md_setkey (*ctx, key, keylen)
4163 +#define libssh2_hmac_md5_init(ctx, key, keylen) \
4164 + gcry_md_open (ctx, GCRY_MD_MD5, GCRY_MD_FLAG_HMAC), \
4165 + gcry_md_setkey (*ctx, key, keylen)
4166 +#define libssh2_hmac_ripemd160_init(ctx, key, keylen) \
4167 + gcry_md_open (ctx, GCRY_MD_RMD160, GCRY_MD_FLAG_HMAC), \
4168 + gcry_md_setkey (*ctx, key, keylen)
4169 +#define libssh2_hmac_update(ctx, data, datalen) \
4170 + gcry_md_write (ctx, data, datalen)
4171 +#define libssh2_hmac_final(ctx, data) \
4172 + memcpy (data, gcry_md_read (ctx, 0), \
4173 + gcry_md_get_algo_dlen (gcry_md_get_algo (ctx)))
4174 +#define libssh2_hmac_cleanup(ctx) gcry_md_close (*ctx);
4176 +#define libssh2_crypto_init() gcry_control (GCRYCTL_DISABLE_SECMEM)
4178 +#define libssh2_rsa_ctx struct gcry_sexp
4180 +int _libssh2_rsa_new(libssh2_rsa_ctx ** rsa,
4181 + const unsigned char *edata,
4182 + unsigned long elen,
4183 + const unsigned char *ndata,
4184 + unsigned long nlen,
4185 + const unsigned char *ddata,
4186 + unsigned long dlen,
4187 + const unsigned char *pdata,
4188 + unsigned long plen,
4189 + const unsigned char *qdata,
4190 + unsigned long qlen,
4191 + const unsigned char *e1data,
4192 + unsigned long e1len,
4193 + const unsigned char *e2data,
4194 + unsigned long e2len,
4195 + const unsigned char *coeffdata, unsigned long coefflen);
4196 +int _libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa,
4197 + LIBSSH2_SESSION * session,
4198 + FILE * fp, unsigned const char *passphrase);
4199 +int _libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsa,
4200 + const unsigned char *sig,
4201 + unsigned long sig_len,
4202 + const unsigned char *m, unsigned long m_len);
4203 +int _libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session,
4204 + libssh2_rsa_ctx * rsactx,
4205 + const unsigned char *hash,
4206 + unsigned long hash_len,
4207 + unsigned char **signature,
4208 + unsigned long *signature_len);
4210 +#define _libssh2_rsa_free(rsactx) gcry_sexp_release (rsactx)
4212 +#define libssh2_dsa_ctx struct gcry_sexp
4214 +int _libssh2_dsa_new(libssh2_dsa_ctx ** dsa,
4215 + const unsigned char *pdata,
4216 + unsigned long plen,
4217 + const unsigned char *qdata,
4218 + unsigned long qlen,
4219 + const unsigned char *gdata,
4220 + unsigned long glen,
4221 + const unsigned char *ydata,
4222 + unsigned long ylen,
4223 + const unsigned char *x, unsigned long x_len);
4224 +int _libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa,
4225 + LIBSSH2_SESSION * session,
4226 + FILE * fp, unsigned const char *passphrase);
4227 +int _libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsa,
4228 + const unsigned char *sig,
4229 + const unsigned char *m, unsigned long m_len);
4230 +int _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,
4231 + const unsigned char *hash,
4232 + unsigned long hash_len, unsigned char *sig);
4234 +#define _libssh2_dsa_free(dsactx) gcry_sexp_release (dsactx)
4236 +#define _libssh2_cipher_type(name) int name
4237 +#define _libssh2_cipher_ctx gcry_cipher_hd_t
4239 +#define _libssh2_cipher_aes256 GCRY_CIPHER_AES256
4240 +#define _libssh2_cipher_aes192 GCRY_CIPHER_AES192
4241 +#define _libssh2_cipher_aes128 GCRY_CIPHER_AES128
4242 +#define _libssh2_cipher_blowfish GCRY_CIPHER_BLOWFISH
4243 +#define _libssh2_cipher_arcfour GCRY_CIPHER_ARCFOUR
4244 +#define _libssh2_cipher_cast5 GCRY_CIPHER_CAST5
4245 +#define _libssh2_cipher_3des GCRY_CIPHER_3DES
4247 +int _libssh2_cipher_init(_libssh2_cipher_ctx * h,
4248 + _libssh2_cipher_type(algo),
4249 + unsigned char *iv,
4250 + unsigned char *secret, int encrypt);
4252 +int _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx,
4253 + _libssh2_cipher_type(algo),
4254 + int encrypt, unsigned char *block);
4256 +#define _libssh2_cipher_dtor(ctx) gcry_cipher_close(*(ctx))
4258 +#define _libssh2_bn struct gcry_mpi
4259 +#define _libssh2_bn_ctx int
4260 +#define _libssh2_bn_ctx_new() 0
4261 +#define _libssh2_bn_ctx_free(bnctx) ((void)0)
4262 +#define _libssh2_bn_init() gcry_mpi_new(0)
4263 +#define _libssh2_bn_rand(bn, bits, top, bottom) gcry_mpi_randomize (bn, bits, GCRY_WEAK_RANDOM)
4264 +#define _libssh2_bn_mod_exp(r, a, p, m, ctx) gcry_mpi_powm (r, a, p, m)
4265 +#define _libssh2_bn_set_word(bn, val) gcry_mpi_set_ui(bn, val)
4266 +#define _libssh2_bn_from_bin(bn, len, val) gcry_mpi_scan(&((bn)), GCRYMPI_FMT_USG, val, len, NULL)
4267 +#define _libssh2_bn_to_bin(bn, val) gcry_mpi_print (GCRYMPI_FMT_USG, val, _libssh2_bn_bytes(bn), NULL, bn)
4268 +#define _libssh2_bn_bytes(bn) (gcry_mpi_get_nbits (bn) / 8 + ((gcry_mpi_get_nbits (bn) % 8 == 0) ? 0 : 1))
4269 +#define _libssh2_bn_bits(bn) gcry_mpi_get_nbits (bn)
4270 +#define _libssh2_bn_free(bn) gcry_mpi_release(bn)
4272 Property changes on: libssh2/src/libgcrypt.h
4273 ___________________________________________________________________
4274 Added: svn:mime-type
4277 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
4278 Added: cvs2svn:cvs-rev
4280 Added: svn:eol-style
4282 Added: svn:executable
4285 Index: libssh2/src/packet.c
4286 ===================================================================
4287 --- libssh2/src/packet.c (.../tags/RELEASE_0_11_0)
4288 +++ libssh2/src/packet.c (.../trunk)
4290 +/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
4291 + * All rights reserved.
4293 + * Redistribution and use in source and binary forms,
4294 + * with or without modification, are permitted provided
4295 + * that the following conditions are met:
4297 + * Redistributions of source code must retain the above
4298 + * copyright notice, this list of conditions and the
4299 + * following disclaimer.
4301 + * Redistributions in binary form must reproduce the above
4302 + * copyright notice, this list of conditions and the following
4303 + * disclaimer in the documentation and/or other materials
4304 + * provided with the distribution.
4306 + * Neither the name of the copyright holder nor the names
4307 + * of any other contributors may be used to endorse or
4308 + * promote products derived from this software without
4309 + * specific prior written permission.
4311 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
4312 + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
4313 + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
4314 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4315 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
4316 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4317 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
4318 + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
4319 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
4320 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
4321 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
4322 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
4323 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
4327 +#include "libssh2_priv.h"
4331 +#ifdef HAVE_UNISTD_H
4332 +#include <unistd.h>
4335 +#ifdef HAVE_SYS_TIME_H
4336 +#include <sys/time.h>
4339 +#ifdef HAVE_INTTYPES_H
4340 +#include <inttypes.h>
4343 +/* Needed for struct iovec on some platforms */
4344 +#ifdef HAVE_SYS_UIO_H
4345 +#include <sys/uio.h>
4348 +#include <sys/types.h>
4350 +/* {{{ libssh2_packet_queue_listener
4351 + * Queue a connection request for a listener
4354 +libssh2_packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data,
4355 + unsigned long datalen,
4356 + packet_queue_listener_state_t * listen_state)
4359 + * Look for a matching listener
4361 + unsigned char *s = data + (sizeof("forwarded-tcpip") - 1) + 5;
4362 + /* 17 = packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */
4363 + unsigned long packet_len = 17 + (sizeof(FwdNotReq) - 1);
4365 + LIBSSH2_LISTENER *listen = session->listeners;
4366 + char failure_code = 1; /* SSH_OPEN_ADMINISTRATIVELY_PROHIBITED */
4371 + if (listen_state->state == libssh2_NB_state_idle) {
4372 + listen_state->sender_channel = libssh2_ntohu32(s);
4375 + listen_state->initial_window_size = libssh2_ntohu32(s);
4377 + listen_state->packet_size = libssh2_ntohu32(s);
4380 + listen_state->host_len = libssh2_ntohu32(s);
4382 + listen_state->host = s;
4383 + s += listen_state->host_len;
4384 + listen_state->port = libssh2_ntohu32(s);
4387 + listen_state->shost_len = libssh2_ntohu32(s);
4389 + listen_state->shost = s;
4390 + s += listen_state->shost_len;
4391 + listen_state->sport = libssh2_ntohu32(s);
4394 + _libssh2_debug(session, LIBSSH2_DBG_CONN,
4395 + "Remote received connection from %s:%ld to %s:%ld",
4396 + listen_state->shost, listen_state->sport,
4397 + listen_state->host, listen_state->port);
4399 + listen_state->state = libssh2_NB_state_allocated;
4402 + if (listen_state->state != libssh2_NB_state_sent) {
4404 + if ((listen->port == (int) listen_state->port) &&
4405 + (strlen(listen->host) == listen_state->host_len) &&
4407 + (listen->host, listen_state->host,
4408 + listen_state->host_len) == 0)) {
4409 + /* This is our listener */
4410 + LIBSSH2_CHANNEL *channel, *last_queued = listen->queue;
4412 + last_queued = listen->queue;
4413 + if (listen_state->state == libssh2_NB_state_allocated) {
4414 + if (listen->queue_maxsize &&
4415 + (listen->queue_maxsize <= listen->queue_size)) {
4416 + /* Queue is full */
4417 + failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */
4418 + _libssh2_debug(session, LIBSSH2_DBG_CONN,
4419 + "Listener queue full, ignoring");
4420 + listen_state->state = libssh2_NB_state_sent;
4424 + channel = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL));
4426 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
4427 + "Unable to allocate a channel for new connection",
4429 + failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */
4430 + listen_state->state = libssh2_NB_state_sent;
4433 + memset(channel, 0, sizeof(LIBSSH2_CHANNEL));
4435 + channel->session = session;
4436 + channel->channel_type_len = sizeof("forwarded-tcpip") - 1;
4437 + channel->channel_type = LIBSSH2_ALLOC(session,
4439 + channel_type_len +
4441 + if (!channel->channel_type) {
4442 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
4443 + "Unable to allocate a channel for new connection",
4445 + LIBSSH2_FREE(session, channel);
4446 + failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */
4447 + listen_state->state = libssh2_NB_state_sent;
4450 + memcpy(channel->channel_type, "forwarded-tcpip",
4451 + channel->channel_type_len + 1);
4453 + channel->remote.id = listen_state->sender_channel;
4454 + channel->remote.window_size_initial =
4455 + LIBSSH2_CHANNEL_WINDOW_DEFAULT;
4456 + channel->remote.window_size =
4457 + LIBSSH2_CHANNEL_WINDOW_DEFAULT;
4458 + channel->remote.packet_size =
4459 + LIBSSH2_CHANNEL_PACKET_DEFAULT;
4461 + channel->local.id = libssh2_channel_nextid(session);
4462 + channel->local.window_size_initial =
4463 + listen_state->initial_window_size;
4464 + channel->local.window_size =
4465 + listen_state->initial_window_size;
4466 + channel->local.packet_size = listen_state->packet_size;
4468 + _libssh2_debug(session, LIBSSH2_DBG_CONN,
4469 + "Connection queued: channel %lu/%lu win %lu/%lu packet %lu/%lu",
4470 + channel->local.id, channel->remote.id,
4471 + channel->local.window_size,
4472 + channel->remote.window_size,
4473 + channel->local.packet_size,
4474 + channel->remote.packet_size);
4476 + p = listen_state->packet;
4477 + *(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION;
4478 + libssh2_htonu32(p, channel->remote.id);
4480 + libssh2_htonu32(p, channel->local.id);
4482 + libssh2_htonu32(p, channel->remote.window_size_initial);
4484 + libssh2_htonu32(p, channel->remote.packet_size);
4487 + listen_state->state = libssh2_NB_state_created;
4490 + if (listen_state->state == libssh2_NB_state_created) {
4491 + rc = libssh2_packet_write(session, listen_state->packet,
4493 + if (rc == PACKET_EAGAIN) {
4494 + return PACKET_EAGAIN;
4496 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
4497 + "Unable to send channel open confirmation",
4499 + listen_state->state = libssh2_NB_state_idle;
4503 + /* Link the channel into the end of the queue list */
4505 + if (!last_queued) {
4506 + listen->queue = channel;
4507 + listen_state->state = libssh2_NB_state_idle;
4511 + while (last_queued->next) {
4512 + last_queued = last_queued->next;
4515 + last_queued->next = channel;
4516 + channel->prev = last_queued;
4518 + listen->queue_size++;
4520 + listen_state->state = libssh2_NB_state_idle;
4525 + listen = listen->next;
4528 + listen_state->state = libssh2_NB_state_sent;
4531 + /* We're not listening to you */
4533 + p = listen_state->packet;
4534 + *(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE;
4535 + libssh2_htonu32(p, listen_state->sender_channel);
4537 + libssh2_htonu32(p, failure_code);
4539 + libssh2_htonu32(p, sizeof(FwdNotReq) - 1);
4541 + memcpy(s, FwdNotReq, sizeof(FwdNotReq) - 1);
4542 + p += sizeof(FwdNotReq) - 1;
4543 + libssh2_htonu32(p, 0);
4545 + rc = libssh2_packet_write(session, listen_state->packet, packet_len);
4546 + if (rc == PACKET_EAGAIN) {
4547 + return PACKET_EAGAIN;
4549 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
4550 + "Unable to send open failure", 0);
4551 + listen_state->state = libssh2_NB_state_idle;
4554 + listen_state->state = libssh2_NB_state_idle;
4561 +/* {{{ libssh2_packet_x11_open
4562 + * Accept a forwarded X11 connection
4565 +libssh2_packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data,
4566 + unsigned long datalen,
4567 + packet_x11_open_state_t * x11open_state)
4569 + int failure_code = 2; /* SSH_OPEN_CONNECT_FAILED */
4570 + unsigned char *s = data + (sizeof("x11") - 1) + 5;
4571 + /* 17 = packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */
4572 + unsigned long packet_len = 17 + (sizeof(X11FwdUnAvil) - 1);
4574 + LIBSSH2_CHANNEL *channel;
4579 + if (x11open_state->state == libssh2_NB_state_idle) {
4580 + x11open_state->sender_channel = libssh2_ntohu32(s);
4582 + x11open_state->initial_window_size = libssh2_ntohu32(s);
4584 + x11open_state->packet_size = libssh2_ntohu32(s);
4586 + x11open_state->shost_len = libssh2_ntohu32(s);
4588 + x11open_state->shost = s;
4589 + s += x11open_state->shost_len;
4590 + x11open_state->sport = libssh2_ntohu32(s);
4593 + _libssh2_debug(session, LIBSSH2_DBG_CONN,
4594 + "X11 Connection Received from %s:%ld on channel %lu",
4595 + x11open_state->shost, x11open_state->sport,
4596 + x11open_state->sender_channel);
4598 + x11open_state->state = libssh2_NB_state_allocated;
4601 + if (session->x11) {
4602 + if (x11open_state->state == libssh2_NB_state_allocated) {
4603 + channel = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL));
4605 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
4606 + "Unable to allocate a channel for new connection",
4608 + failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */
4611 + memset(channel, 0, sizeof(LIBSSH2_CHANNEL));
4613 + channel->session = session;
4614 + channel->channel_type_len = sizeof("x11") - 1;
4615 + channel->channel_type = LIBSSH2_ALLOC(session,
4616 + channel->channel_type_len +
4618 + if (!channel->channel_type) {
4619 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
4620 + "Unable to allocate a channel for new connection",
4622 + LIBSSH2_FREE(session, channel);
4623 + failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */
4626 + memcpy(channel->channel_type, "x11",
4627 + channel->channel_type_len + 1);
4629 + channel->remote.id = x11open_state->sender_channel;
4630 + channel->remote.window_size_initial =
4631 + LIBSSH2_CHANNEL_WINDOW_DEFAULT;
4632 + channel->remote.window_size = LIBSSH2_CHANNEL_WINDOW_DEFAULT;
4633 + channel->remote.packet_size = LIBSSH2_CHANNEL_PACKET_DEFAULT;
4635 + channel->local.id = libssh2_channel_nextid(session);
4636 + channel->local.window_size_initial =
4637 + x11open_state->initial_window_size;
4638 + channel->local.window_size = x11open_state->initial_window_size;
4639 + channel->local.packet_size = x11open_state->packet_size;
4641 + _libssh2_debug(session, LIBSSH2_DBG_CONN,
4642 + "X11 Connection established: channel %lu/%lu win %lu/%lu packet %lu/%lu",
4643 + channel->local.id, channel->remote.id,
4644 + channel->local.window_size,
4645 + channel->remote.window_size,
4646 + channel->local.packet_size,
4647 + channel->remote.packet_size);
4648 + p = x11open_state->packet;
4649 + *(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION;
4650 + libssh2_htonu32(p, channel->remote.id);
4652 + libssh2_htonu32(p, channel->local.id);
4654 + libssh2_htonu32(p, channel->remote.window_size_initial);
4656 + libssh2_htonu32(p, channel->remote.packet_size);
4659 + x11open_state->state = libssh2_NB_state_created;
4662 + if (x11open_state->state == libssh2_NB_state_created) {
4663 + rc = libssh2_packet_write(session, x11open_state->packet, 17);
4664 + if (rc == PACKET_EAGAIN) {
4665 + return PACKET_EAGAIN;
4667 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
4668 + "Unable to send channel open confirmation", 0);
4669 + x11open_state->state = libssh2_NB_state_idle;
4673 + /* Link the channel into the session */
4674 + if (session->channels.tail) {
4675 + session->channels.tail->next = channel;
4676 + channel->prev = session->channels.tail;
4678 + session->channels.head = channel;
4679 + channel->prev = NULL;
4681 + channel->next = NULL;
4682 + session->channels.tail = channel;
4685 + * Pass control to the callback, they may turn right around and
4686 + * free the channel, or actually use it
4688 + LIBSSH2_X11_OPEN(channel, (char *) x11open_state->shost,
4689 + x11open_state->sport);
4691 + x11open_state->state = libssh2_NB_state_idle;
4695 + failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */
4699 + p = x11open_state->packet;
4700 + *(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE;
4701 + libssh2_htonu32(p, x11open_state->sender_channel);
4703 + libssh2_htonu32(p, failure_code);
4705 + libssh2_htonu32(p, sizeof(X11FwdUnAvil) - 1);
4707 + memcpy(s, X11FwdUnAvil, sizeof(X11FwdUnAvil) - 1);
4708 + p += sizeof(X11FwdUnAvil) - 1;
4709 + libssh2_htonu32(p, 0);
4711 + rc = libssh2_packet_write(session, x11open_state->packet, packet_len);
4712 + if (rc == PACKET_EAGAIN) {
4713 + return PACKET_EAGAIN;
4715 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
4716 + "Unable to send open failure", 0);
4717 + x11open_state->state = libssh2_NB_state_idle;
4720 + x11open_state->state = libssh2_NB_state_idle;
4726 +/* {{{ libssh2_packet_new
4727 + * Create a new packet and attach it to the brigade
4730 +libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
4731 + size_t datalen, int macstate)
4735 + if (session->packAdd_state == libssh2_NB_state_idle) {
4736 + session->packAdd_data_head = 0;
4738 + /* Zero the whole thing out */
4739 + memset(&session->packAdd_key_state, 0,
4740 + sizeof(session->packAdd_key_state));
4742 + /* Zero the whole thing out */
4743 + memset(&session->packAdd_Qlstn_state, 0,
4744 + sizeof(session->packAdd_Qlstn_state));
4746 + /* Zero the whole thing out */
4747 + memset(&session->packAdd_x11open_state, 0,
4748 + sizeof(session->packAdd_x11open_state));
4750 + _libssh2_debug(session, LIBSSH2_DBG_TRANS,
4751 + "Packet type %d received, length=%d",
4752 + (int) data[0], (int) datalen);
4753 + if (macstate == LIBSSH2_MAC_INVALID) {
4754 + if (session->macerror) {
4755 + if (LIBSSH2_MACERROR(session, (char *) data, datalen) == 0) {
4756 + /* Calling app has given the OK, Process it anyway */
4757 + macstate = LIBSSH2_MAC_CONFIRMED;
4759 + libssh2_error(session, LIBSSH2_ERROR_INVALID_MAC,
4760 + "Invalid Message Authentication Code received",
4762 + if (session->ssh_msg_disconnect) {
4763 + LIBSSH2_DISCONNECT(session, SSH_DISCONNECT_MAC_ERROR,
4764 + "Invalid MAC received",
4765 + sizeof("Invalid MAC received") - 1,
4768 + LIBSSH2_FREE(session, data);
4772 + libssh2_error(session, LIBSSH2_ERROR_INVALID_MAC,
4773 + "Invalid Message Authentication Code received",
4775 + if (session->ssh_msg_disconnect) {
4776 + LIBSSH2_DISCONNECT(session, SSH_DISCONNECT_MAC_ERROR,
4777 + "Invalid MAC received",
4778 + sizeof("Invalid MAC received") - 1,
4781 + LIBSSH2_FREE(session, data);
4786 + session->packAdd_state = libssh2_NB_state_allocated;
4790 + * =============================== NOTE ===============================
4791 + * I know this is very ugly and not a really good use of "goto", but
4792 + * this case statement would be even uglier to do it any other way
4794 + if (session->packAdd_state == libssh2_NB_state_jump1) {
4795 + goto libssh2_packet_add_jump_point1;
4796 + } else if (session->packAdd_state == libssh2_NB_state_jump2) {
4797 + goto libssh2_packet_add_jump_point2;
4798 + } else if (session->packAdd_state == libssh2_NB_state_jump3) {
4799 + goto libssh2_packet_add_jump_point3;
4802 + if (session->packAdd_state == libssh2_NB_state_allocated) {
4803 + /* A couple exceptions to the packet adding rule: */
4804 + switch (data[0]) {
4805 + case SSH_MSG_DISCONNECT:
4807 + char *message, *language;
4808 + int reason, message_len, language_len;
4810 + reason = libssh2_ntohu32(data + 1);
4811 + message_len = libssh2_ntohu32(data + 5);
4812 + /* 9 = packet_type(1) + reason(4) + message_len(4) */
4813 + message = (char *) data + 9;
4814 + language_len = libssh2_ntohu32(data + 9 + message_len);
4816 + * This is where we hack on the data a little,
4817 + * Use the MSB of language_len to to a terminating NULL
4818 + * (In all liklihood it is already)
4819 + * Shift the language tag back a byte (In all likelihood
4820 + * it's zero length anyway)
4821 + * Store a NULL in the last byte of the packet to terminate
4822 + * the language string
4823 + * With the lengths passed this isn't *REALLY* necessary,
4826 + message[message_len] = '\0';
4827 + language = (char *) data + 9 + message_len + 3;
4828 + if (language_len) {
4829 + memcpy(language, language + 1, language_len);
4831 + language[language_len] = '\0';
4833 + if (session->ssh_msg_disconnect) {
4834 + LIBSSH2_DISCONNECT(session, reason, message,
4835 + message_len, language, language_len);
4837 + _libssh2_debug(session, LIBSSH2_DBG_TRANS,
4838 + "Disconnect(%d): %s(%s)", reason,
4839 + message, language);
4840 + LIBSSH2_FREE(session, data);
4841 + session->socket_state = LIBSSH2_SOCKET_DISCONNECTED;
4842 + session->packAdd_state = libssh2_NB_state_idle;
4847 + case SSH_MSG_IGNORE:
4848 + /* As with disconnect, back it up one and add a trailing NULL */
4849 + memcpy(data + 4, data + 5, datalen - 5);
4850 + data[datalen] = '\0';
4851 + if (session->ssh_msg_ignore) {
4852 + LIBSSH2_IGNORE(session, (char *) data + 4, datalen - 5);
4854 + LIBSSH2_FREE(session, data);
4855 + session->packAdd_state = libssh2_NB_state_idle;
4859 + case SSH_MSG_DEBUG:
4861 + int always_display = data[0];
4862 + char *message, *language;
4863 + int message_len, language_len;
4865 + message_len = libssh2_ntohu32(data + 2);
4866 + /* 6 = packet_type(1) + display(1) + message_len(4) */
4867 + message = (char *) data + 6;
4868 + language_len = libssh2_ntohu32(data + 6 + message_len);
4870 + * This is where we hack on the data a little,
4871 + * Use the MSB of language_len to to a terminating NULL
4872 + * (In all liklihood it is already)
4873 + * Shift the language tag back a byte (In all likelihood
4874 + * it's zero length anyway)
4875 + * Store a NULL in the last byte of the packet to terminate
4876 + * the language string
4877 + * With the lengths passed this isn't *REALLY* necessary,
4880 + message[message_len] = '\0';
4881 + language = (char *) data + 6 + message_len + 3;
4882 + if (language_len) {
4883 + memcpy(language, language + 1, language_len);
4885 + language[language_len] = '\0';
4887 + if (session->ssh_msg_debug) {
4888 + LIBSSH2_DEBUG(session, always_display, message,
4889 + message_len, language, language_len);
4892 + * _libssh2_debug will actually truncate this for us so
4893 + * that it's not an inordinate about of data
4895 + _libssh2_debug(session, LIBSSH2_DBG_TRANS,
4896 + "Debug Packet: %s", message);
4897 + LIBSSH2_FREE(session, data);
4898 + session->packAdd_state = libssh2_NB_state_idle;
4903 + case SSH_MSG_CHANNEL_EXTENDED_DATA:
4905 + session->packAdd_data_head += 4;
4906 + case SSH_MSG_CHANNEL_DATA:
4907 + /* packet_type(1) + channelno(4) + datalen(4) */
4908 + session->packAdd_data_head += 9;
4910 + session->packAdd_channel = libssh2_channel_locate(session,
4914 + if (!session->packAdd_channel) {
4915 + libssh2_error(session, LIBSSH2_ERROR_CHANNEL_UNKNOWN,
4916 + "Packet received for unknown channel, ignoring",
4918 + LIBSSH2_FREE(session, data);
4919 + session->packAdd_state = libssh2_NB_state_idle;
4922 +#ifdef LIBSSH2DEBUG
4924 + unsigned long stream_id = 0;
4926 + if (data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) {
4927 + stream_id = libssh2_ntohu32(data + 5);
4930 + _libssh2_debug(session, LIBSSH2_DBG_CONN,
4931 + "%d bytes received for channel %lu/%lu stream #%lu",
4933 + session->packAdd_data_head),
4934 + session->packAdd_channel->local.id,
4935 + session->packAdd_channel->remote.id,
4939 + if ((session->packAdd_channel->remote.
4940 + extended_data_ignore_mode ==
4941 + LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE)
4942 + && (data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA)) {
4943 + /* Pretend we didn't receive this */
4944 + LIBSSH2_FREE(session, data);
4946 + _libssh2_debug(session, LIBSSH2_DBG_CONN,
4947 + "Ignoring extended data and refunding %d bytes",
4948 + (int) (datalen - 13));
4949 + /* Adjust the window based on the block we just freed */
4950 + libssh2_packet_add_jump_point1:
4951 + session->packAdd_state = libssh2_NB_state_jump1;
4952 + rc = libssh2_channel_receive_window_adjust(session->
4956 + if (rc == PACKET_EAGAIN) {
4957 + session->socket_block_directions =
4958 + LIBSSH2_SESSION_BLOCK_OUTBOUND;
4959 + return PACKET_EAGAIN;
4961 + session->packAdd_state = libssh2_NB_state_idle;
4966 + * REMEMBER! remote means remote as source of data,
4967 + * NOT remote window!
4969 + if (session->packAdd_channel->remote.packet_size <
4970 + (datalen - session->packAdd_data_head)) {
4972 + * Spec says we MAY ignore bytes sent beyond
4975 + libssh2_error(session,
4976 + LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED,
4977 + "Packet contains more data than we offered to receive, truncating",
4980 + session->packAdd_channel->remote.packet_size +
4981 + session->packAdd_data_head;
4983 + if (session->packAdd_channel->remote.window_size <= 0) {
4985 + * Spec says we MAY ignore bytes sent beyond
4988 + libssh2_error(session,
4989 + LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED,
4990 + "The current receive window is full, data ignored",
4992 + LIBSSH2_FREE(session, data);
4993 + session->packAdd_state = libssh2_NB_state_idle;
4996 + /* Reset EOF status */
4997 + session->packAdd_channel->remote.eof = 0;
4999 + if ((datalen - session->packAdd_data_head) >
5000 + session->packAdd_channel->remote.window_size) {
5001 + libssh2_error(session,
5002 + LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED,
5003 + "Remote sent more data than current window allows, truncating",
5006 + session->packAdd_channel->remote.window_size +
5007 + session->packAdd_data_head;
5009 + /* Now that we've received it, shrink our window */
5010 + session->packAdd_channel->remote.window_size -=
5011 + datalen - session->packAdd_data_head;
5016 + case SSH_MSG_CHANNEL_EOF:
5018 + session->packAdd_channel = libssh2_channel_locate(session,
5022 + if (!session->packAdd_channel) {
5023 + /* We may have freed already, just quietly ignore this... */
5024 + LIBSSH2_FREE(session, data);
5025 + session->packAdd_state = libssh2_NB_state_idle;
5029 + _libssh2_debug(session,
5031 + "EOF received for channel %lu/%lu",
5032 + session->packAdd_channel->local.id,
5033 + session->packAdd_channel->remote.id);
5034 + session->packAdd_channel->remote.eof = 1;
5036 + LIBSSH2_FREE(session, data);
5037 + session->packAdd_state = libssh2_NB_state_idle;
5042 + case SSH_MSG_CHANNEL_REQUEST:
5044 + if (libssh2_ntohu32(data + 5) == sizeof("exit-status") - 1
5045 + && !memcmp("exit-status", data + 9,
5046 + sizeof("exit-status") - 1)) {
5048 + /* we've got "exit-status" packet. Set the session value */
5049 + session->packAdd_channel =
5050 + libssh2_channel_locate(session,
5051 + libssh2_ntohu32(data + 1));
5053 + if (session->packAdd_channel) {
5054 + session->packAdd_channel->exit_status =
5055 + libssh2_ntohu32(data + 9 + sizeof("exit-status"));
5056 + _libssh2_debug(session, LIBSSH2_DBG_CONN,
5057 + "Exit status %lu received for channel %lu/%lu",
5058 + session->packAdd_channel->exit_status,
5059 + session->packAdd_channel->local.id,
5060 + session->packAdd_channel->remote.id);
5063 + LIBSSH2_FREE(session, data);
5064 + session->packAdd_state = libssh2_NB_state_idle;
5070 + case SSH_MSG_CHANNEL_CLOSE:
5072 + session->packAdd_channel = libssh2_channel_locate(session,
5076 + if (!session->packAdd_channel) {
5077 + /* We may have freed already, just quietly ignore this... */
5078 + LIBSSH2_FREE(session, data);
5079 + session->packAdd_state = libssh2_NB_state_idle;
5082 + _libssh2_debug(session, LIBSSH2_DBG_CONN,
5083 + "Close received for channel %lu/%lu",
5084 + session->packAdd_channel->local.id,
5085 + session->packAdd_channel->remote.id);
5087 + session->packAdd_channel->remote.close = 1;
5088 + session->packAdd_channel->remote.eof = 1;
5089 + /* TODO: Add a callback for this */
5091 + LIBSSH2_FREE(session, data);
5092 + session->packAdd_state = libssh2_NB_state_idle;
5097 + case SSH_MSG_CHANNEL_OPEN:
5098 + if ((datalen >= (sizeof("forwarded-tcpip") + 4)) &&
5099 + ((sizeof("forwarded-tcpip") - 1) == libssh2_ntohu32(data + 1))
5102 + (data + 5, "forwarded-tcpip",
5103 + sizeof("forwarded-tcpip") - 1) == 0)) {
5105 + libssh2_packet_add_jump_point2:
5106 + session->packAdd_state = libssh2_NB_state_jump2;
5107 + rc = libssh2_packet_queue_listener(session, data, datalen,
5109 + packAdd_Qlstn_state);
5110 + if (rc == PACKET_EAGAIN) {
5111 + session->socket_block_directions =
5112 + LIBSSH2_SESSION_BLOCK_OUTBOUND;
5113 + return PACKET_EAGAIN;
5116 + LIBSSH2_FREE(session, data);
5117 + session->packAdd_state = libssh2_NB_state_idle;
5120 + if ((datalen >= (sizeof("x11") + 4)) &&
5121 + ((sizeof("x11") - 1) == libssh2_ntohu32(data + 1)) &&
5122 + (memcmp(data + 5, "x11", sizeof("x11") - 1) == 0)) {
5124 + libssh2_packet_add_jump_point3:
5125 + session->packAdd_state = libssh2_NB_state_jump3;
5126 + rc = libssh2_packet_x11_open(session, data, datalen,
5127 + &session->packAdd_x11open_state);
5128 + if (rc == PACKET_EAGAIN) {
5129 + session->socket_block_directions =
5130 + LIBSSH2_SESSION_BLOCK_OUTBOUND;
5131 + return PACKET_EAGAIN;
5134 + LIBSSH2_FREE(session, data);
5135 + session->packAdd_state = libssh2_NB_state_idle;
5140 + case SSH_MSG_CHANNEL_WINDOW_ADJUST:
5142 + unsigned long bytestoadd = libssh2_ntohu32(data + 5);
5143 + session->packAdd_channel = libssh2_channel_locate(session,
5147 + if (session->packAdd_channel && bytestoadd) {
5148 + session->packAdd_channel->local.window_size += bytestoadd;
5150 + _libssh2_debug(session, LIBSSH2_DBG_CONN,
5151 + "Window adjust received for channel %lu/%lu, adding %lu bytes, new window_size=%lu",
5152 + session->packAdd_channel->local.id,
5153 + session->packAdd_channel->remote.id,
5155 + session->packAdd_channel->local.window_size);
5157 + LIBSSH2_FREE(session, data);
5158 + session->packAdd_state = libssh2_NB_state_idle;
5164 + session->packAdd_state = libssh2_NB_state_sent;
5167 + if (session->packAdd_state == libssh2_NB_state_sent) {
5168 + session->packAdd_packet =
5169 + LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PACKET));
5170 + if (!session->packAdd_packet) {
5171 + _libssh2_debug(session, LIBSSH2_ERROR_ALLOC,
5172 + "Unable to allocate memory for LIBSSH2_PACKET");
5173 + LIBSSH2_FREE(session, data);
5174 + session->packAdd_state = libssh2_NB_state_idle;
5177 + memset(session->packAdd_packet, 0, sizeof(LIBSSH2_PACKET));
5179 + session->packAdd_packet->data = data;
5180 + session->packAdd_packet->data_len = datalen;
5181 + session->packAdd_packet->data_head = session->packAdd_data_head;
5182 + session->packAdd_packet->mac = macstate;
5183 + session->packAdd_packet->brigade = &session->packets;
5184 + session->packAdd_packet->next = NULL;
5186 + if (session->packets.tail) {
5187 + session->packAdd_packet->prev = session->packets.tail;
5188 + session->packAdd_packet->prev->next = session->packAdd_packet;
5189 + session->packets.tail = session->packAdd_packet;
5191 + session->packets.head = session->packAdd_packet;
5192 + session->packets.tail = session->packAdd_packet;
5193 + session->packAdd_packet->prev = NULL;
5196 + session->packAdd_state = libssh2_NB_state_sent1;
5199 + if ((data[0] == SSH_MSG_KEXINIT &&
5200 + !(session->state & LIBSSH2_STATE_EXCHANGING_KEYS)) ||
5201 + (session->packAdd_state == libssh2_NB_state_sent2)) {
5202 + if (session->packAdd_state == libssh2_NB_state_sent1) {
5204 + * Remote wants new keys
5205 + * Well, it's already in the brigade,
5206 + * let's just call back into ourselves
5208 + _libssh2_debug(session, LIBSSH2_DBG_TRANS, "Renegotiating Keys");
5210 + session->packAdd_state = libssh2_NB_state_sent2;
5214 + * The KEXINIT message has been added to the queue.
5215 + * The packAdd and readPack states need to be reset
5216 + * because libssh2_kex_exchange (eventually) calls upon
5217 + * libssh2_packet_read to read the rest of the key exchange
5220 + session->readPack_state = libssh2_NB_state_idle;
5221 + session->packet.total_num = 0;
5222 + session->packAdd_state = libssh2_NB_state_idle;
5223 + session->fullpacket_state = libssh2_NB_state_idle;
5226 + * Also, don't use packAdd_key_state for key re-exchange,
5227 + * as it will be wiped out in the middle of the exchange.
5228 + * How about re-using the startup_key_state?
5230 + memset(&session->startup_key_state, 0, sizeof(key_exchange_state_t));
5233 + * If there was a key reexchange failure, let's just hope we didn't
5234 + * send NEWKEYS yet, otherwise remote will drop us like a rock
5236 + rc = libssh2_kex_exchange(session, 1, &session->startup_key_state);
5237 + if (rc == PACKET_EAGAIN) {
5238 + return PACKET_EAGAIN;
5242 + session->packAdd_state = libssh2_NB_state_idle;
5248 +/* {{{ libssh2_packet_ask
5249 + * Scan the brigade for a matching packet type, optionally poll the socket for
5253 +libssh2_packet_ask_ex(LIBSSH2_SESSION * session, unsigned char packet_type,
5254 + unsigned char **data, unsigned long *data_len,
5255 + unsigned long match_ofs, const unsigned char *match_buf,
5256 + unsigned long match_len, int poll_socket)
5258 + LIBSSH2_PACKET *packet = session->packets.head;
5260 + if (poll_socket) {
5263 + * When "poll_socket" is "1" libhss2_packet_read() can return
5264 + * PACKET_EAGAIN. I am not sure what should happen, but internally
5265 + * there is only one location that might do so, libssh2_packet_askv_ex()
5267 + libssh2pack_t rc = libssh2_packet_read(session);
5268 + if ((rc < 0) && !packet) {
5272 + _libssh2_debug(session, LIBSSH2_DBG_TRANS,
5273 + "Looking for packet of type: %d", (int) packet_type);
5276 + if (packet->data[0] == packet_type
5277 + && (packet->data_len >= (match_ofs + match_len)) && (!match_buf
5286 + *data = packet->data;
5287 + *data_len = packet->data_len;
5289 + if (packet->prev) {
5290 + packet->prev->next = packet->next;
5292 + session->packets.head = packet->next;
5295 + if (packet->next) {
5296 + packet->next->prev = packet->prev;
5298 + session->packets.tail = packet->prev;
5301 + LIBSSH2_FREE(session, packet);
5305 + packet = packet->next;
5312 +/* {{{ libssh2_packet_askv
5313 + * Scan for any of a list of packet types in the brigade, optionally poll the
5314 + * socket for a packet first
5317 +libssh2_packet_askv_ex(LIBSSH2_SESSION * session,
5318 + const unsigned char *packet_types,
5319 + unsigned char **data, unsigned long *data_len,
5320 + unsigned long match_ofs,
5321 + const unsigned char *match_buf,
5322 + unsigned long match_len, int poll_socket)
5324 + int i, packet_types_len = strlen((char *) packet_types);
5326 + for(i = 0; i < packet_types_len; i++) {
5329 + * When "poll_socket" is "1" libssh2_packet_ask_ex() could
5330 + * return PACKET_EAGAIN. Not sure the correct action, I
5331 + * think it is right as is.
5333 + if (0 == libssh2_packet_ask_ex(session, packet_types[i], data,
5334 + data_len, match_ofs, match_buf,
5335 + match_len, i ? 0 : poll_socket)) {
5347 + * negative on error
5348 + * >0 on incoming data
5351 + * FIXME: convert to use poll on systems that have it.
5354 +libssh2_waitsocket(LIBSSH2_SESSION * session, long seconds)
5356 + struct timeval timeout;
5360 + timeout.tv_sec = seconds;
5361 + timeout.tv_usec = 0;
5365 + FD_SET(session->socket_fd, &fd);
5367 + rc = select(session->socket_fd + 1, &fd, NULL, NULL, &timeout);
5372 +/* {{{ libssh2_packet_require
5373 + * Loops libssh2_packet_read() until the packet requested is available
5374 + * SSH_DISCONNECT or a SOCKET_DISCONNECTED will cause a bailout
5376 + * Returns negative on error
5377 + * Returns 0 when it has taken care of the requested packet.
5380 +libssh2_packet_require_ex(LIBSSH2_SESSION * session, unsigned char packet_type,
5381 + unsigned char **data, unsigned long *data_len,
5382 + unsigned long match_ofs,
5383 + const unsigned char *match_buf,
5384 + unsigned long match_len,
5385 + packet_require_state_t * state)
5387 + if (state->start == 0) {
5388 + if (libssh2_packet_ask_ex
5389 + (session, packet_type, data, data_len, match_ofs, match_buf,
5390 + match_len, 0) == 0) {
5391 + /* A packet was available in the packet brigade */
5395 + state->start = time(NULL);
5397 + _libssh2_debug(session, LIBSSH2_DBG_TRANS,
5398 + "May block until packet of type %d becomes available",
5399 + (int) packet_type);
5402 + while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
5403 + libssh2pack_t ret = libssh2_packet_read(session);
5404 + if (ret == PACKET_EAGAIN) {
5405 + return PACKET_EAGAIN;
5406 + } else if ((ret == 0) && (!session->socket_block)) {
5407 + /* If we are in non-blocking and there is no data, return that */
5408 + return PACKET_EAGAIN;
5409 + } else if (ret < 0) {
5411 + /* an error which is not just because of blocking */
5413 + } else if (ret == packet_type) {
5414 + /* Be lazy, let packet_ask pull it out of the brigade */
5416 + libssh2_packet_ask_ex(session, packet_type, data, data_len,
5417 + match_ofs, match_buf, match_len, 0);
5420 + } else if (ret == 0) {
5421 + /* nothing available, wait until data arrives or we time out */
5422 + long left = LIBSSH2_READ_TIMEOUT - (time(NULL) - state->start);
5424 + if ((left <= 0) || (libssh2_waitsocket(session, left) <= 0)) {
5426 + return PACKET_TIMEOUT;
5431 + /* Only reached if the socket died */
5437 +/* {{{ libssh2_packet_burn
5438 + * Loops libssh2_packet_read() until any packet is available and promptly
5440 + * Used during KEX exchange to discard badly guessed KEX_INIT packets
5443 +libssh2_packet_burn(LIBSSH2_SESSION * session,
5444 + libssh2_nonblocking_states * state)
5446 + unsigned char *data;
5447 + unsigned long data_len;
5448 + unsigned char all_packets[255];
5452 + if (*state == libssh2_NB_state_idle) {
5453 + for(i = 1; i < 256; i++) {
5454 + all_packets[i - 1] = i;
5457 + if (libssh2_packet_askv_ex
5458 + (session, all_packets, &data, &data_len, 0, NULL, 0, 0) == 0) {
5460 + /* A packet was available in the packet brigade, burn it */
5461 + LIBSSH2_FREE(session, data);
5465 + _libssh2_debug(session, LIBSSH2_DBG_TRANS,
5466 + "Blocking until packet becomes available to burn");
5467 + *state = libssh2_NB_state_created;
5470 + while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
5471 + if ((ret = libssh2_packet_read(session)) == PACKET_EAGAIN) {
5472 + return PACKET_EAGAIN;
5473 + } else if (ret < 0) {
5474 + *state = libssh2_NB_state_idle;
5476 + } else if (ret == 0) {
5477 + /* FIXME: this might busyloop */
5481 + /* Be lazy, let packet_ask pull it out of the brigade */
5483 + libssh2_packet_ask_ex(session, ret, &data, &data_len, 0, NULL, 0,
5485 + /* Smoke 'em if you got 'em */
5486 + LIBSSH2_FREE(session, data);
5487 + *state = libssh2_NB_state_idle;
5492 + /* Only reached if the socket died */
5499 + * {{{ libssh2_packet_requirev
5501 + * Loops libssh2_packet_read() until one of a list of packet types requested is
5503 + * SSH_DISCONNECT or a SOCKET_DISCONNECTED will cause a bailout
5504 + * packet_types is a null terminated list of packet_type numbers
5508 +libssh2_packet_requirev_ex(LIBSSH2_SESSION * session,
5509 + const unsigned char *packet_types,
5510 + unsigned char **data, unsigned long *data_len,
5511 + unsigned long match_ofs,
5512 + const unsigned char *match_buf,
5513 + unsigned long match_len,
5514 + packet_requirev_state_t * state)
5516 + if (libssh2_packet_askv_ex
5517 + (session, packet_types, data, data_len, match_ofs, match_buf,
5518 + match_len, 0) == 0) {
5519 + /* One of the packets listed was available in the packet
5525 + if (state->start == 0) {
5526 + state->start = time(NULL);
5529 + while (session->socket_state != LIBSSH2_SOCKET_DISCONNECTED) {
5530 + int ret = libssh2_packet_read(session);
5531 + if ((ret < 0) && (ret != PACKET_EAGAIN)) {
5536 + long left = LIBSSH2_READ_TIMEOUT - (time(NULL) - state->start);
5538 + if ((left <= 0) || (libssh2_waitsocket(session, left) <= 0)) {
5540 + return PACKET_TIMEOUT;
5541 + } else if (ret == PACKET_EAGAIN) {
5542 + return PACKET_EAGAIN;
5546 + if (strchr((char *) packet_types, ret)) {
5547 + /* Be lazy, let packet_ask pull it out of the brigade */
5548 + return libssh2_packet_askv_ex(session, packet_types, data,
5549 + data_len, match_ofs, match_buf,
5554 + /* Only reached if the socket died */
5561 Property changes on: libssh2/src/packet.c
5562 ___________________________________________________________________
5563 Added: svn:mime-type
5566 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
5567 Added: cvs2svn:cvs-rev
5569 Added: svn:eol-style
5572 Index: libssh2/src/channel.c
5573 ===================================================================
5574 --- libssh2/src/channel.c (.../tags/RELEASE_0_11_0)
5575 +++ libssh2/src/channel.c (.../trunk)
5577 +/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
5578 + * Copyright (c) 2008 by Daniel Stenberg
5580 + * All rights reserved.
5582 + * Redistribution and use in source and binary forms,
5583 + * with or without modification, are permitted provided
5584 + * that the following conditions are met:
5586 + * Redistributions of source code must retain the above
5587 + * copyright notice, this list of conditions and the
5588 + * following disclaimer.
5590 + * Redistributions in binary form must reproduce the above
5591 + * copyright notice, this list of conditions and the following
5592 + * disclaimer in the documentation and/or other materials
5593 + * provided with the distribution.
5595 + * Neither the name of the copyright holder nor the names
5596 + * of any other contributors may be used to endorse or
5597 + * promote products derived from this software without
5598 + * specific prior written permission.
5600 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
5601 + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
5602 + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
5603 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5604 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
5605 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
5606 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
5607 + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
5608 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
5609 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
5610 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
5611 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
5612 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
5616 +#include "libssh2_priv.h"
5617 +#ifdef HAVE_UNISTD_H
5618 +#include <unistd.h>
5621 +#ifdef HAVE_INTTYPES_H
5622 +#include <inttypes.h>
5626 +/* {{{ libssh2_channel_nextid
5627 + * Determine the next channel ID we can use at our end
5630 +libssh2_channel_nextid(LIBSSH2_SESSION * session)
5632 + unsigned long id = session->next_channel;
5633 + LIBSSH2_CHANNEL *channel;
5635 + channel = session->channels.head;
5638 + if (channel->local.id > id) {
5639 + id = channel->local.id;
5641 + channel = channel->next;
5644 + /* This is a shortcut to avoid waiting for close packets on channels we've
5645 + * forgotten about, This *could* be a problem if we request and close 4
5646 + * billion or so channels in too rapid succession for the remote end to
5647 + * respond, but the worst case scenario is that some data meant for
5648 + * another channel Gets picked up by the new one.... Pretty unlikely all
5651 + session->next_channel = id + 1;
5652 + _libssh2_debug(session, LIBSSH2_DBG_CONN, "Allocated new channel ID#%lu",
5659 +/* {{{ libssh2_channel_locate
5660 + * Locate a channel pointer by number
5663 +libssh2_channel_locate(LIBSSH2_SESSION * session, unsigned long channel_id)
5665 + LIBSSH2_CHANNEL *channel = session->channels.head;
5667 + if (channel->local.id == channel_id) {
5670 + channel = channel->next;
5678 +#define CHANNEL_ADD(session, channel) \
5680 + if ((session)->channels.tail) { \
5681 + (session)->channels.tail->next = (channel); \
5682 + (channel)->prev = (session)->channels.tail; \
5684 + (session)->channels.head = (channel); \
5685 + (channel)->prev = NULL; \
5687 + (channel)->next = NULL; \
5688 + (session)->channels.tail = (channel); \
5689 + (channel)->session = (session); \
5692 +/* {{{ libssh2_channel_open_ex
5693 + * Establish a generic session channel
5695 +LIBSSH2_API LIBSSH2_CHANNEL *
5696 +libssh2_channel_open_ex(LIBSSH2_SESSION * session, const char *channel_type,
5697 + unsigned int channel_type_len,
5698 + unsigned int window_size, unsigned int packet_size,
5699 + const char *message, unsigned int message_len)
5701 + static const unsigned char reply_codes[3] = {
5702 + SSH_MSG_CHANNEL_OPEN_CONFIRMATION,
5703 + SSH_MSG_CHANNEL_OPEN_FAILURE,
5709 + if (session->open_state == libssh2_NB_state_idle) {
5710 + session->open_channel = NULL;
5711 + session->open_packet = NULL;
5712 + session->open_data = NULL;
5713 + /* 17 = packet_type(1) + channel_type_len(4) + sender_channel(4) +
5714 + * window_size(4) + packet_size(4) */
5715 + session->open_packet_len = channel_type_len + message_len + 17;
5716 + session->open_local_channel = libssh2_channel_nextid(session);
5718 + /* Zero the whole thing out */
5719 + memset(&session->open_packet_requirev_state, 0,
5720 + sizeof(session->open_packet_requirev_state));
5722 + _libssh2_debug(session, LIBSSH2_DBG_CONN,
5723 + "Opening Channel - win %d pack %d", window_size,
5725 + session->open_channel =
5726 + LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL));
5727 + if (!session->open_channel) {
5728 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
5729 + "Unable to allocate space for channel data", 0);
5732 + memset(session->open_channel, 0, sizeof(LIBSSH2_CHANNEL));
5734 + session->open_channel->channel_type_len = channel_type_len;
5735 + session->open_channel->channel_type =
5736 + LIBSSH2_ALLOC(session, channel_type_len);
5737 + if (!session->open_channel->channel_type) {
5738 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
5739 + "Failed allocating memory for channel type name", 0);
5740 + LIBSSH2_FREE(session, session->open_channel);
5741 + session->open_channel = NULL;
5744 + memcpy(session->open_channel->channel_type, channel_type,
5745 + channel_type_len);
5747 + /* REMEMBER: local as in locally sourced */
5748 + session->open_channel->local.id = session->open_local_channel;
5749 + session->open_channel->remote.window_size = window_size;
5750 + session->open_channel->remote.window_size_initial = window_size;
5751 + session->open_channel->remote.packet_size = packet_size;
5753 + CHANNEL_ADD(session, session->open_channel);
5755 + s = session->open_packet =
5756 + LIBSSH2_ALLOC(session, session->open_packet_len);
5757 + if (!session->open_packet) {
5758 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
5759 + "Unable to allocate temporary space for packet", 0);
5760 + goto channel_error;
5762 + *(s++) = SSH_MSG_CHANNEL_OPEN;
5763 + libssh2_htonu32(s, channel_type_len);
5766 + memcpy(s, channel_type, channel_type_len);
5767 + s += channel_type_len;
5769 + libssh2_htonu32(s, session->open_local_channel);
5772 + libssh2_htonu32(s, window_size);
5775 + libssh2_htonu32(s, packet_size);
5778 + if (message && message_len) {
5779 + memcpy(s, message, message_len);
5783 + session->open_state = libssh2_NB_state_created;
5786 + if (session->open_state == libssh2_NB_state_created) {
5787 + rc = libssh2_packet_write(session, session->open_packet,
5788 + session->open_packet_len);
5789 + if (rc == PACKET_EAGAIN) {
5790 + libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
5791 + "Would block sending channel-open request", 0);
5794 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
5795 + "Unable to send channel-open request", 0);
5796 + goto channel_error;
5799 + session->open_state = libssh2_NB_state_sent;
5802 + if (session->open_state == libssh2_NB_state_sent) {
5803 + rc = libssh2_packet_requirev_ex(session, reply_codes,
5804 + &session->open_data,
5805 + &session->open_data_len, 1,
5806 + session->open_packet + 5 +
5807 + channel_type_len, 4,
5808 + &session->open_packet_requirev_state);
5809 + if (rc == PACKET_EAGAIN) {
5810 + libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block", 0);
5813 + goto channel_error;
5816 + if (session->open_data[0] == SSH_MSG_CHANNEL_OPEN_CONFIRMATION) {
5817 + session->open_channel->remote.id =
5818 + libssh2_ntohu32(session->open_data + 5);
5819 + session->open_channel->local.window_size =
5820 + libssh2_ntohu32(session->open_data + 9);
5821 + session->open_channel->local.window_size_initial =
5822 + libssh2_ntohu32(session->open_data + 9);
5823 + session->open_channel->local.packet_size =
5824 + libssh2_ntohu32(session->open_data + 13);
5825 + _libssh2_debug(session, LIBSSH2_DBG_CONN,
5826 + "Connection Established - ID: %lu/%lu win: %lu/%lu"
5828 + session->open_channel->local.id,
5829 + session->open_channel->remote.id,
5830 + session->open_channel->local.window_size,
5831 + session->open_channel->remote.window_size,
5832 + session->open_channel->local.packet_size,
5833 + session->open_channel->remote.packet_size);
5834 + LIBSSH2_FREE(session, session->open_packet);
5835 + session->open_packet = NULL;
5836 + LIBSSH2_FREE(session, session->open_data);
5837 + session->open_data = NULL;
5839 + session->open_state = libssh2_NB_state_idle;
5840 + return session->open_channel;
5843 + if (session->open_data[0] == SSH_MSG_CHANNEL_OPEN_FAILURE) {
5844 + libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE,
5845 + "Channel open failure", 0);
5851 + if (session->open_data) {
5852 + LIBSSH2_FREE(session, session->open_data);
5853 + session->open_data = NULL;
5855 + if (session->open_packet) {
5856 + LIBSSH2_FREE(session, session->open_packet);
5857 + session->open_packet = NULL;
5859 + if (session->open_channel) {
5860 + unsigned char channel_id[4];
5861 + LIBSSH2_FREE(session, session->open_channel->channel_type);
5863 + if (session->open_channel->next) {
5864 + session->open_channel->next->prev = session->open_channel->prev;
5866 + if (session->open_channel->prev) {
5867 + session->open_channel->prev->next = session->open_channel->next;
5869 + if (session->channels.head == session->open_channel) {
5870 + session->channels.head = session->open_channel->next;
5872 + if (session->channels.tail == session->open_channel) {
5873 + session->channels.tail = session->open_channel->prev;
5876 + /* Clear out packets meant for this channel */
5877 + libssh2_htonu32(channel_id, session->open_channel->local.id);
5878 + while ((libssh2_packet_ask_ex
5879 + (session, SSH_MSG_CHANNEL_DATA, &session->open_data,
5880 + &session->open_data_len, 1, channel_id, 4, 0) >= 0)
5882 + (libssh2_packet_ask_ex
5883 + (session, SSH_MSG_CHANNEL_EXTENDED_DATA, &session->open_data,
5884 + &session->open_data_len, 1, channel_id, 4, 0) >= 0)) {
5885 + LIBSSH2_FREE(session, session->open_data);
5886 + session->open_data = NULL;
5889 + /* Free any state variables still holding data */
5890 + if (session->open_channel->write_packet) {
5891 + LIBSSH2_FREE(session, session->open_channel->write_packet);
5892 + session->open_channel->write_packet = NULL;
5895 + LIBSSH2_FREE(session, session->open_channel);
5896 + session->open_channel = NULL;
5899 + session->open_state = libssh2_NB_state_idle;
5905 +/* {{{ libssh2_channel_direct_tcpip_ex
5906 + * Tunnel TCP/IP connect through the SSH session to direct host/port
5908 +LIBSSH2_API LIBSSH2_CHANNEL *
5909 +libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION * session, const char *host,
5910 + int port, const char *shost, int sport)
5912 + LIBSSH2_CHANNEL *channel;
5915 + if (session->direct_state == libssh2_NB_state_idle) {
5916 + session->direct_host_len = strlen(host);
5917 + session->direct_shost_len = strlen(shost);
5918 + /* host_len(4) + port(4) + shost_len(4) + sport(4) */
5919 + session->direct_message_len =
5920 + session->direct_host_len + session->direct_shost_len + 16;
5922 + _libssh2_debug(session, LIBSSH2_DBG_CONN,
5923 + "Requesting direct-tcpip session to from %s:%d to %s:%d",
5924 + shost, sport, host, port);
5926 + s = session->direct_message =
5927 + LIBSSH2_ALLOC(session, session->direct_message_len);
5928 + if (!session->direct_message) {
5929 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
5930 + "Unable to allocate memory for direct-tcpip connection",
5934 + libssh2_htonu32(s, session->direct_host_len);
5936 + memcpy(s, host, session->direct_host_len);
5937 + s += session->direct_host_len;
5938 + libssh2_htonu32(s, port);
5941 + libssh2_htonu32(s, session->direct_shost_len);
5943 + memcpy(s, shost, session->direct_shost_len);
5944 + s += session->direct_shost_len;
5945 + libssh2_htonu32(s, sport);
5948 + session->direct_state = libssh2_NB_state_created;
5952 + libssh2_channel_open_ex(session, "direct-tcpip",
5953 + sizeof("direct-tcpip") - 1,
5954 + LIBSSH2_CHANNEL_WINDOW_DEFAULT,
5955 + LIBSSH2_CHANNEL_PACKET_DEFAULT,
5956 + (char *) session->direct_message,
5957 + session->direct_message_len);
5959 + if (libssh2_session_last_errno(session) == LIBSSH2_ERROR_EAGAIN) {
5960 + /* The error code is still set to LIBSSH2_ERROR_EAGAIN */
5963 + LIBSSH2_FREE(session, session->direct_message);
5964 + session->direct_message = NULL;
5969 + LIBSSH2_FREE(session, session->direct_message);
5970 + session->direct_message = NULL;
5977 +/* {{{ libssh2_channel_forward_listen_ex
5978 + * Bind a port on the remote host and listen for connections
5980 +LIBSSH2_API LIBSSH2_LISTENER *
5981 +libssh2_channel_forward_listen_ex(LIBSSH2_SESSION * session, const char *host,
5982 + int port, int *bound_port, int queue_maxsize)
5984 + unsigned char *s, *data;
5985 + static const unsigned char reply_codes[3] =
5986 + { SSH_MSG_REQUEST_SUCCESS, SSH_MSG_REQUEST_FAILURE, 0 };
5987 + unsigned long data_len;
5990 + if (session->fwdLstn_state == libssh2_NB_state_idle) {
5991 + session->fwdLstn_host_len =
5992 + (host ? strlen(host) : (sizeof("0.0.0.0") - 1));
5993 + /* 14 = packet_type(1) + request_len(4) + want_replay(1) + host_len(4)
5995 + session->fwdLstn_packet_len =
5996 + session->fwdLstn_host_len + (sizeof("tcpip-forward") - 1) + 14;
5998 + /* Zero the whole thing out */
5999 + memset(&session->fwdLstn_packet_requirev_state, 0,
6000 + sizeof(session->fwdLstn_packet_requirev_state));
6002 + _libssh2_debug(session, LIBSSH2_DBG_CONN,
6003 + "Requesting tcpip-forward session for %s:%d", host,
6006 + s = session->fwdLstn_packet =
6007 + LIBSSH2_ALLOC(session, session->fwdLstn_packet_len);
6008 + if (!session->fwdLstn_packet) {
6009 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
6010 + "Unable to allocate memeory for setenv packet", 0);
6014 + *(s++) = SSH_MSG_GLOBAL_REQUEST;
6015 + libssh2_htonu32(s, sizeof("tcpip-forward") - 1);
6017 + memcpy(s, "tcpip-forward", sizeof("tcpip-forward") - 1);
6018 + s += sizeof("tcpip-forward") - 1;
6019 + *(s++) = 0x01; /* want_reply */
6021 + libssh2_htonu32(s, session->fwdLstn_host_len);
6023 + memcpy(s, host ? host : "0.0.0.0", session->fwdLstn_host_len);
6024 + s += session->fwdLstn_host_len;
6025 + libssh2_htonu32(s, port);
6028 + session->fwdLstn_state = libssh2_NB_state_created;
6031 + if (session->fwdLstn_state == libssh2_NB_state_created) {
6032 + rc = libssh2_packet_write(session, session->fwdLstn_packet,
6033 + session->fwdLstn_packet_len);
6034 + if (rc == PACKET_EAGAIN) {
6035 + libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
6036 + "Would block sending global-request packet for "
6037 + "forward listen request",
6041 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
6042 + "Unable to send global-request packet for forward "
6045 + LIBSSH2_FREE(session, session->fwdLstn_packet);
6046 + session->fwdLstn_packet = NULL;
6047 + session->fwdLstn_state = libssh2_NB_state_idle;
6050 + LIBSSH2_FREE(session, session->fwdLstn_packet);
6051 + session->fwdLstn_packet = NULL;
6053 + session->fwdLstn_state = libssh2_NB_state_sent;
6056 + if (session->fwdLstn_state == libssh2_NB_state_sent) {
6057 + rc = libssh2_packet_requirev_ex(session, reply_codes, &data, &data_len,
6060 + fwdLstn_packet_requirev_state);
6061 + if (rc == PACKET_EAGAIN) {
6062 + libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block", 0);
6065 + libssh2_error(session, LIBSSH2_ERROR_PROTO, "Unknown", 0);
6066 + session->fwdLstn_state = libssh2_NB_state_idle;
6070 + if (data[0] == SSH_MSG_REQUEST_SUCCESS) {
6071 + LIBSSH2_LISTENER *listener;
6073 + listener = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_LISTENER));
6075 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
6076 + "Unable to allocate memory for listener queue",
6078 + LIBSSH2_FREE(session, data);
6079 + session->fwdLstn_state = libssh2_NB_state_idle;
6082 + memset(listener, 0, sizeof(LIBSSH2_LISTENER));
6083 + listener->session = session;
6085 + LIBSSH2_ALLOC(session, session->fwdLstn_host_len + 1);
6086 + if (!listener->host) {
6087 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
6088 + "Unable to allocate memory for listener queue",
6090 + LIBSSH2_FREE(session, listener);
6091 + LIBSSH2_FREE(session, data);
6092 + session->fwdLstn_state = libssh2_NB_state_idle;
6095 + memcpy(listener->host, host ? host : "0.0.0.0",
6096 + session->fwdLstn_host_len);
6097 + listener->host[session->fwdLstn_host_len] = 0;
6098 + if (data_len >= 5 && !port) {
6099 + listener->port = libssh2_ntohu32(data + 1);
6100 + _libssh2_debug(session, LIBSSH2_DBG_CONN,
6101 + "Dynamic tcpip-forward port allocated: %d",
6104 + listener->port = port;
6107 + listener->queue_size = 0;
6108 + listener->queue_maxsize = queue_maxsize;
6110 + listener->next = session->listeners;
6111 + listener->prev = NULL;
6112 + if (session->listeners) {
6113 + session->listeners->prev = listener;
6115 + session->listeners = listener;
6118 + *bound_port = listener->port;
6121 + LIBSSH2_FREE(session, data);
6122 + session->fwdLstn_state = libssh2_NB_state_idle;
6126 + if (data[0] == SSH_MSG_REQUEST_FAILURE) {
6127 + LIBSSH2_FREE(session, data);
6128 + libssh2_error(session, LIBSSH2_ERROR_REQUEST_DENIED,
6129 + "Unable to complete request for forward-listen", 0);
6130 + session->fwdLstn_state = libssh2_NB_state_idle;
6135 + session->fwdLstn_state = libssh2_NB_state_idle;
6142 +/* {{{ libssh2_channel_forward_cancel
6143 + * Stop listening on a remote port and free the listener
6144 + * Toss out any pending (un-accept()ed) connections
6146 + * Return 0 on success, PACKET_EAGAIN if would block, -1 on error
6149 +libssh2_channel_forward_cancel(LIBSSH2_LISTENER * listener)
6151 + LIBSSH2_SESSION *session = listener->session;
6152 + LIBSSH2_CHANNEL *queued = listener->queue;
6153 + unsigned char *packet, *s;
6154 + unsigned long host_len = strlen(listener->host);
6155 + /* 14 = packet_type(1) + request_len(4) + want_replay(1) + host_len(4) +
6157 + unsigned long packet_len =
6158 + host_len + 14 + sizeof("cancel-tcpip-forward") - 1;
6161 + if (listener->chanFwdCncl_state == libssh2_NB_state_idle) {
6162 + _libssh2_debug(session, LIBSSH2_DBG_CONN,
6163 + "Cancelling tcpip-forward session for %s:%d",
6164 + listener->host, listener->port);
6166 + s = packet = LIBSSH2_ALLOC(session, packet_len);
6168 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
6169 + "Unable to allocate memeory for setenv packet", 0);
6173 + *(s++) = SSH_MSG_GLOBAL_REQUEST;
6174 + libssh2_htonu32(s, sizeof("cancel-tcpip-forward") - 1);
6176 + memcpy(s, "cancel-tcpip-forward", sizeof("cancel-tcpip-forward") - 1);
6177 + s += sizeof("cancel-tcpip-forward") - 1;
6178 + *(s++) = 0x00; /* want_reply */
6180 + libssh2_htonu32(s, host_len);
6182 + memcpy(s, listener->host, host_len);
6184 + libssh2_htonu32(s, listener->port);
6187 + listener->chanFwdCncl_state = libssh2_NB_state_created;
6189 + packet = listener->chanFwdCncl_data;
6192 + if (listener->chanFwdCncl_state == libssh2_NB_state_created) {
6193 + rc = libssh2_packet_write(session, packet, packet_len);
6194 + if (rc == PACKET_EAGAIN) {
6195 + listener->chanFwdCncl_data = packet;
6197 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
6198 + "Unable to send global-request packet for forward "
6201 + LIBSSH2_FREE(session, packet);
6202 + listener->chanFwdCncl_state = libssh2_NB_state_idle;
6205 + LIBSSH2_FREE(session, packet);
6207 + listener->chanFwdCncl_state = libssh2_NB_state_sent;
6211 + LIBSSH2_CHANNEL *next = queued->next;
6213 + rc = libssh2_channel_free(queued);
6214 + if (rc == PACKET_EAGAIN) {
6215 + return PACKET_EAGAIN;
6219 + LIBSSH2_FREE(session, listener->host);
6221 + if (listener->next) {
6222 + listener->next->prev = listener->prev;
6224 + if (listener->prev) {
6225 + listener->prev->next = listener->next;
6227 + session->listeners = listener->next;
6230 + LIBSSH2_FREE(session, listener);
6232 + listener->chanFwdCncl_state = libssh2_NB_state_idle;
6239 +/* {{{ libssh2_channel_forward_accept
6240 + * Accept a connection
6242 +LIBSSH2_API LIBSSH2_CHANNEL *
6243 +libssh2_channel_forward_accept(LIBSSH2_LISTENER * listener)
6248 + rc = libssh2_packet_read(listener->session);
6249 + if (rc == PACKET_EAGAIN) {
6250 + libssh2_error(listener->session, LIBSSH2_ERROR_EAGAIN,
6251 + "Would block waiting for packet", 0);
6256 + if (listener->queue) {
6257 + LIBSSH2_SESSION *session = listener->session;
6258 + LIBSSH2_CHANNEL *channel;
6260 + channel = listener->queue;
6262 + listener->queue = listener->queue->next;
6263 + if (listener->queue) {
6264 + listener->queue->prev = NULL;
6267 + channel->prev = NULL;
6268 + channel->next = session->channels.head;
6269 + session->channels.head = channel;
6271 + if (channel->next) {
6272 + channel->next->prev = channel;
6274 + session->channels.tail = channel;
6276 + listener->queue_size--;
6286 +/* {{{ libssh2_channel_setenv_ex
6287 + * Set an environment variable prior to requesting a shell/program/subsystem
6290 +libssh2_channel_setenv_ex(LIBSSH2_CHANNEL * channel, const char *varname,
6291 + unsigned int varname_len, const char *value,
6292 + unsigned int value_len)
6294 + LIBSSH2_SESSION *session = channel->session;
6295 + unsigned char *s, *data;
6296 + static const unsigned char reply_codes[3] =
6297 + { SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 };
6298 + unsigned long data_len;
6301 + if (channel->setenv_state == libssh2_NB_state_idle) {
6302 + /* 21 = packet_type(1) + channel_id(4) + request_len(4) +
6303 + * request(3)"env" + want_reply(1) + varname_len(4) + value_len(4) */
6304 + channel->setenv_packet_len = varname_len + value_len + 21;
6306 + /* Zero the whole thing out */
6307 + memset(&channel->setenv_packet_requirev_state, 0,
6308 + sizeof(channel->setenv_packet_requirev_state));
6310 + _libssh2_debug(session, LIBSSH2_DBG_CONN,
6311 + "Setting remote environment variable: %s=%s on "
6312 + "channel %lu/%lu",
6313 + varname, value, channel->local.id, channel->remote.id);
6315 + s = channel->setenv_packet =
6316 + LIBSSH2_ALLOC(session, channel->setenv_packet_len);
6317 + if (!channel->setenv_packet) {
6318 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
6319 + "Unable to allocate memeory for setenv packet", 0);
6323 + *(s++) = SSH_MSG_CHANNEL_REQUEST;
6324 + libssh2_htonu32(s, channel->remote.id);
6326 + libssh2_htonu32(s, sizeof("env") - 1);
6328 + memcpy(s, "env", sizeof("env") - 1);
6329 + s += sizeof("env") - 1;
6333 + libssh2_htonu32(s, varname_len);
6335 + memcpy(s, varname, varname_len);
6338 + libssh2_htonu32(s, value_len);
6340 + memcpy(s, value, value_len);
6343 + channel->setenv_state = libssh2_NB_state_created;
6346 + if (channel->setenv_state == libssh2_NB_state_created) {
6347 + rc = libssh2_packet_write(session, channel->setenv_packet,
6348 + channel->setenv_packet_len);
6349 + if (rc == PACKET_EAGAIN) {
6350 + return PACKET_EAGAIN;
6352 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
6353 + "Unable to send channel-request packet for "
6356 + LIBSSH2_FREE(session, channel->setenv_packet);
6357 + channel->setenv_packet = NULL;
6358 + channel->setenv_state = libssh2_NB_state_idle;
6361 + LIBSSH2_FREE(session, channel->setenv_packet);
6362 + channel->setenv_packet = NULL;
6364 + libssh2_htonu32(channel->setenv_local_channel, channel->local.id);
6366 + channel->setenv_state = libssh2_NB_state_sent;
6369 + if (channel->setenv_state == libssh2_NB_state_sent) {
6370 + rc = libssh2_packet_requirev_ex(session, reply_codes, &data, &data_len,
6371 + 1, channel->setenv_local_channel, 4,
6373 + setenv_packet_requirev_state);
6374 + if (rc == PACKET_EAGAIN) {
6375 + return PACKET_EAGAIN;
6378 + channel->setenv_state = libssh2_NB_state_idle;
6382 + if (data[0] == SSH_MSG_CHANNEL_SUCCESS) {
6383 + LIBSSH2_FREE(session, data);
6384 + channel->setenv_state = libssh2_NB_state_idle;
6388 + LIBSSH2_FREE(session, data);
6391 + libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED,
6392 + "Unable to complete request for channel-setenv", 0);
6393 + channel->setenv_state = libssh2_NB_state_idle;
6399 +/* {{{ libssh2_channel_request_pty_ex
6400 + * Duh... Request a PTY
6403 +libssh2_channel_request_pty_ex(LIBSSH2_CHANNEL * channel, const char *term,
6404 + unsigned int term_len, const char *modes,
6405 + unsigned int modes_len, int width, int height,
6406 + int width_px, int height_px)
6408 + LIBSSH2_SESSION *session = channel->session;
6409 + unsigned char *s, *data;
6410 + static const unsigned char reply_codes[3] =
6411 + { SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 };
6412 + unsigned long data_len;
6415 + if (channel->reqPTY_state == libssh2_NB_state_idle) {
6416 + /* 41 = packet_type(1) + channel(4) + pty_req_len(4) + "pty_req"(7) +
6417 + * want_reply(1) + term_len(4) + width(4) + height(4) + width_px(4) +
6418 + * height_px(4) + modes_len(4) */
6419 + channel->reqPTY_packet_len = term_len + modes_len + 41;
6421 + /* Zero the whole thing out */
6422 + memset(&channel->reqPTY_packet_requirev_state, 0,
6423 + sizeof(channel->reqPTY_packet_requirev_state));
6425 + _libssh2_debug(session, LIBSSH2_DBG_CONN,
6426 + "Allocating tty on channel %lu/%lu", channel->local.id,
6427 + channel->remote.id);
6429 + s = channel->reqPTY_packet =
6430 + LIBSSH2_ALLOC(session, channel->reqPTY_packet_len);
6431 + if (!channel->reqPTY_packet) {
6432 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
6433 + "Unable to allocate memory for pty-request", 0);
6437 + *(s++) = SSH_MSG_CHANNEL_REQUEST;
6438 + libssh2_htonu32(s, channel->remote.id);
6440 + libssh2_htonu32(s, sizeof("pty-req") - 1);
6442 + memcpy(s, "pty-req", sizeof("pty-req") - 1);
6443 + s += sizeof("pty-req") - 1;
6447 + libssh2_htonu32(s, term_len);
6450 + memcpy(s, term, term_len);
6454 + libssh2_htonu32(s, width);
6456 + libssh2_htonu32(s, height);
6458 + libssh2_htonu32(s, width_px);
6460 + libssh2_htonu32(s, height_px);
6463 + libssh2_htonu32(s, modes_len);
6466 + memcpy(s, modes, modes_len);
6470 + channel->reqPTY_state = libssh2_NB_state_created;
6473 + if (channel->reqPTY_state == libssh2_NB_state_created) {
6474 + rc = libssh2_packet_write(session, channel->reqPTY_packet,
6475 + channel->reqPTY_packet_len);
6476 + if (rc == PACKET_EAGAIN) {
6477 + return PACKET_EAGAIN;
6479 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
6480 + "Unable to send pty-request packet", 0);
6481 + LIBSSH2_FREE(session, channel->reqPTY_packet);
6482 + channel->reqPTY_packet = NULL;
6483 + channel->reqPTY_state = libssh2_NB_state_idle;
6486 + LIBSSH2_FREE(session, channel->reqPTY_packet);
6487 + channel->reqPTY_packet = NULL;
6489 + libssh2_htonu32(channel->reqPTY_local_channel, channel->local.id);
6491 + channel->reqPTY_state = libssh2_NB_state_sent;
6494 + if (channel->reqPTY_state == libssh2_NB_state_sent) {
6495 + rc = libssh2_packet_requirev_ex(session, reply_codes, &data, &data_len,
6496 + 1, channel->reqPTY_local_channel, 4,
6498 + reqPTY_packet_requirev_state);
6499 + if (rc == PACKET_EAGAIN) {
6500 + return PACKET_EAGAIN;
6502 + channel->reqPTY_state = libssh2_NB_state_idle;
6506 + if (data[0] == SSH_MSG_CHANNEL_SUCCESS) {
6507 + LIBSSH2_FREE(session, data);
6508 + channel->reqPTY_state = libssh2_NB_state_idle;
6513 + LIBSSH2_FREE(session, data);
6514 + libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED,
6515 + "Unable to complete request for channel request-pty", 0);
6516 + channel->reqPTY_state = libssh2_NB_state_idle;
6523 +libssh2_channel_request_pty_size_ex(LIBSSH2_CHANNEL * channel, int width,
6524 + int height, int width_px, int height_px)
6526 + LIBSSH2_SESSION *session = channel->session;
6530 + if (channel->reqPTY_state == libssh2_NB_state_idle) {
6531 + channel->reqPTY_packet_len = 39;
6533 + /* Zero the whole thing out */
6534 + memset(&channel->reqPTY_packet_requirev_state, 0,
6535 + sizeof(channel->reqPTY_packet_requirev_state));
6537 + _libssh2_debug(session, LIBSSH2_DBG_CONN,
6538 + "changing tty size on channel %lu/%lu",
6539 + channel->local.id,
6540 + channel->remote.id);
6542 + s = channel->reqPTY_packet =
6543 + LIBSSH2_ALLOC(session, channel->reqPTY_packet_len);
6545 + if (!channel->reqPTY_packet) {
6546 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
6547 + "Unable to allocate memory for pty-request", 0);
6551 + *(s++) = SSH_MSG_CHANNEL_REQUEST;
6552 + libssh2_htonu32(s, channel->remote.id);
6554 + libssh2_htonu32(s, sizeof("window-change") - 1);
6556 + memcpy(s, "window-change", sizeof("window-change") - 1);
6557 + s += sizeof("window-change") - 1;
6559 + *(s++) = 0x00; /* Don't reply */
6560 + libssh2_htonu32(s, width);
6562 + libssh2_htonu32(s, height);
6564 + libssh2_htonu32(s, width_px);
6566 + libssh2_htonu32(s, height_px);
6569 + channel->reqPTY_state = libssh2_NB_state_created;
6572 + if (channel->reqPTY_state == libssh2_NB_state_created) {
6573 + rc = libssh2_packet_write(session, channel->reqPTY_packet,
6574 + channel->reqPTY_packet_len);
6575 + if (rc == PACKET_EAGAIN) {
6576 + return PACKET_EAGAIN;
6578 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
6579 + "Unable to send window-change packet", 0);
6580 + LIBSSH2_FREE(session, channel->reqPTY_packet);
6581 + channel->reqPTY_packet = NULL;
6582 + channel->reqPTY_state = libssh2_NB_state_idle;
6585 + LIBSSH2_FREE(session, channel->reqPTY_packet);
6586 + channel->reqPTY_packet = NULL;
6587 + libssh2_htonu32(channel->reqPTY_local_channel, channel->local.id);
6588 + channel->reqPTY_state = libssh2_NB_state_sent;
6593 + channel->reqPTY_state = libssh2_NB_state_idle;
6597 +/* Keep this an even number */
6598 +#define LIBSSH2_X11_RANDOM_COOKIE_LEN 32
6600 +/* {{{ libssh2_channel_x11_req_ex
6601 + * Request X11 forwarding
6604 +libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL * channel, int single_connection,
6605 + const char *auth_proto, const char *auth_cookie,
6606 + int screen_number)
6608 + LIBSSH2_SESSION *session = channel->session;
6609 + unsigned char *s, *data;
6610 + static const unsigned char reply_codes[3] =
6611 + { SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 };
6612 + unsigned long data_len;
6613 + unsigned long proto_len =
6614 + auth_proto ? strlen(auth_proto) : (sizeof("MIT-MAGIC-COOKIE-1") - 1);
6615 + unsigned long cookie_len =
6616 + auth_cookie ? strlen(auth_cookie) : LIBSSH2_X11_RANDOM_COOKIE_LEN;
6619 + if (channel->reqX11_state == libssh2_NB_state_idle) {
6620 + /* 30 = packet_type(1) + channel(4) + x11_req_len(4) + "x11-req"(7) +
6621 + * want_reply(1) + single_cnx(1) + proto_len(4) + cookie_len(4) +
6622 + * screen_num(4) */
6623 + channel->reqX11_packet_len = proto_len + cookie_len + 30;
6625 + /* Zero the whole thing out */
6626 + memset(&channel->reqX11_packet_requirev_state, 0,
6627 + sizeof(channel->reqX11_packet_requirev_state));
6629 + _libssh2_debug(session, LIBSSH2_DBG_CONN,
6630 + "Requesting x11-req for channel %lu/%lu: single=%d "
6631 + "proto=%s cookie=%s screen=%d",
6632 + channel->local.id, channel->remote.id,
6633 + single_connection,
6634 + auth_proto ? auth_proto : "MIT-MAGIC-COOKIE-1",
6635 + auth_cookie ? auth_cookie : "<random>", screen_number);
6637 + s = channel->reqX11_packet =
6638 + LIBSSH2_ALLOC(session, channel->reqX11_packet_len);
6639 + if (!channel->reqX11_packet) {
6640 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
6641 + "Unable to allocate memory for pty-request", 0);
6645 + *(s++) = SSH_MSG_CHANNEL_REQUEST;
6646 + libssh2_htonu32(s, channel->remote.id);
6648 + libssh2_htonu32(s, sizeof("x11-req") - 1);
6650 + memcpy(s, "x11-req", sizeof("x11-req") - 1);
6651 + s += sizeof("x11-req") - 1;
6653 + *(s++) = 0x01; /* want_reply */
6654 + *(s++) = single_connection ? 0x01 : 0x00;
6656 + libssh2_htonu32(s, proto_len);
6658 + memcpy(s, auth_proto ? auth_proto : "MIT-MAGIC-COOKIE-1", proto_len);
6661 + libssh2_htonu32(s, cookie_len);
6663 + if (auth_cookie) {
6664 + memcpy(s, auth_cookie, cookie_len);
6667 + unsigned char buffer[LIBSSH2_X11_RANDOM_COOKIE_LEN / 2];
6669 + libssh2_random(buffer, LIBSSH2_X11_RANDOM_COOKIE_LEN / 2);
6670 + for(i = 0; i < (LIBSSH2_X11_RANDOM_COOKIE_LEN / 2); i++) {
6671 + snprintf((char *) s + (i * 2), 2, "%02X", buffer[i]);
6676 + libssh2_htonu32(s, screen_number);
6679 + channel->reqX11_state = libssh2_NB_state_created;
6682 + if (channel->reqX11_state == libssh2_NB_state_created) {
6683 + rc = libssh2_packet_write(session, channel->reqX11_packet,
6684 + channel->reqX11_packet_len);
6685 + if (rc == PACKET_EAGAIN) {
6686 + return PACKET_EAGAIN;
6689 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
6690 + "Unable to send x11-req packet", 0);
6691 + LIBSSH2_FREE(session, channel->reqX11_packet);
6692 + channel->reqX11_packet = NULL;
6693 + channel->reqX11_state = libssh2_NB_state_idle;
6696 + LIBSSH2_FREE(session, channel->reqX11_packet);
6697 + channel->reqX11_packet = NULL;
6699 + libssh2_htonu32(channel->reqX11_local_channel, channel->local.id);
6701 + channel->reqX11_state = libssh2_NB_state_sent;
6704 + if (channel->reqX11_state == libssh2_NB_state_sent) {
6705 + rc = libssh2_packet_requirev_ex(session, reply_codes, &data, &data_len,
6706 + 1, channel->reqX11_local_channel, 4,
6708 + reqX11_packet_requirev_state);
6709 + if (rc == PACKET_EAGAIN) {
6710 + return PACKET_EAGAIN;
6712 + channel->reqX11_state = libssh2_NB_state_idle;
6716 + if (data[0] == SSH_MSG_CHANNEL_SUCCESS) {
6717 + LIBSSH2_FREE(session, data);
6718 + channel->reqX11_state = libssh2_NB_state_idle;
6723 + LIBSSH2_FREE(session, data);
6724 + libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED,
6725 + "Unable to complete request for channel x11-req", 0);
6731 +/* {{{ libssh2_channel_process_startup
6732 + * Primitive for libssh2_channel_(shell|exec|subsystem)
6735 +libssh2_channel_process_startup(LIBSSH2_CHANNEL * channel, const char *request,
6736 + unsigned int request_len, const char *message,
6737 + unsigned int message_len)
6739 + LIBSSH2_SESSION *session = channel->session;
6740 + unsigned char *s, *data;
6741 + static const unsigned char reply_codes[3] =
6742 + { SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 };
6743 + unsigned long data_len;
6746 + if (channel->process_state == libssh2_NB_state_idle) {
6747 + /* 10 = packet_type(1) + channel(4) + request_len(4) + want_reply(1) */
6748 + channel->process_packet_len = request_len + 10;
6750 + /* Zero the whole thing out */
6751 + memset(&channel->process_packet_requirev_state, 0,
6752 + sizeof(channel->process_packet_requirev_state));
6755 + channel->process_packet_len += message_len + 4;
6758 + _libssh2_debug(session, LIBSSH2_DBG_CONN,
6759 + "starting request(%s) on channel %lu/%lu, message=%s",
6760 + request, channel->local.id, channel->remote.id,
6762 + s = channel->process_packet =
6763 + LIBSSH2_ALLOC(session, channel->process_packet_len);
6764 + if (!channel->process_packet) {
6765 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
6766 + "Unable to allocate memory for channel-process request",
6771 + *(s++) = SSH_MSG_CHANNEL_REQUEST;
6772 + libssh2_htonu32(s, channel->remote.id);
6774 + libssh2_htonu32(s, request_len);
6776 + memcpy(s, request, request_len);
6782 + libssh2_htonu32(s, message_len);
6784 + memcpy(s, message, message_len);
6788 + channel->process_state = libssh2_NB_state_created;
6791 + if (channel->process_state == libssh2_NB_state_created) {
6792 + rc = libssh2_packet_write(session, channel->process_packet,
6793 + channel->process_packet_len);
6794 + if (rc == PACKET_EAGAIN) {
6795 + return PACKET_EAGAIN;
6797 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
6798 + "Unable to send channel request", 0);
6799 + LIBSSH2_FREE(session, channel->process_packet);
6800 + channel->process_packet = NULL;
6801 + channel->process_state = libssh2_NB_state_idle;
6804 + LIBSSH2_FREE(session, channel->process_packet);
6805 + channel->process_packet = NULL;
6807 + libssh2_htonu32(channel->process_local_channel, channel->local.id);
6809 + channel->process_state = libssh2_NB_state_sent;
6812 + if (channel->process_state == libssh2_NB_state_sent) {
6813 + rc = libssh2_packet_requirev_ex(session, reply_codes, &data, &data_len,
6814 + 1, channel->process_local_channel, 4,
6816 + process_packet_requirev_state);
6817 + if (rc == PACKET_EAGAIN) {
6818 + return PACKET_EAGAIN;
6820 + channel->process_state = libssh2_NB_state_idle;
6824 + if (data[0] == SSH_MSG_CHANNEL_SUCCESS) {
6825 + LIBSSH2_FREE(session, data);
6826 + channel->process_state = libssh2_NB_state_idle;
6831 + LIBSSH2_FREE(session, data);
6832 + libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED,
6833 + "Unable to complete request for channel-process-startup", 0);
6834 + channel->process_state = libssh2_NB_state_idle;
6840 +/* {{{ libssh2_channel_set_blocking
6841 + * Set a channel's blocking mode on or off, similar to a socket's
6842 + * fcntl(fd, F_SETFL, O_NONBLOCK); type command
6845 +libssh2_channel_set_blocking(LIBSSH2_CHANNEL * channel, int blocking)
6847 + (void) _libssh2_session_set_blocking(channel->session, blocking);
6852 +/* {{{ libssh2_channel_flush_ex
6853 + * Flush data from one (or all) stream
6854 + * Returns number of bytes flushed, or -1 on failure
6857 +libssh2_channel_flush_ex(LIBSSH2_CHANNEL * channel, int streamid)
6859 + LIBSSH2_PACKET *packet = channel->session->packets.head;
6861 + if (channel->flush_state == libssh2_NB_state_idle) {
6862 + channel->flush_refund_bytes = 0;
6863 + channel->flush_flush_bytes = 0;
6866 + LIBSSH2_PACKET *next = packet->next;
6867 + unsigned char packet_type = packet->data[0];
6869 + if (((packet_type == SSH_MSG_CHANNEL_DATA)
6870 + || (packet_type == SSH_MSG_CHANNEL_EXTENDED_DATA))
6871 + && (libssh2_ntohu32(packet->data + 1) == channel->local.id)) {
6872 + /* It's our channel at least */
6873 + long packet_stream_id =
6875 + SSH_MSG_CHANNEL_DATA) ? 0 : libssh2_ntohu32(packet->data +
6877 + if ((streamid == LIBSSH2_CHANNEL_FLUSH_ALL)
6878 + || ((packet_type == SSH_MSG_CHANNEL_EXTENDED_DATA)
6879 + && ((streamid == LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA)
6880 + || (streamid == packet_stream_id)))
6881 + || ((packet_type == SSH_MSG_CHANNEL_DATA)
6882 + && (streamid == 0))) {
6883 + int bytes_to_flush = packet->data_len - packet->data_head;
6885 + _libssh2_debug(channel->session, LIBSSH2_DBG_CONN,
6886 + "Flushing %d bytes of data from stream "
6887 + "%lu on channel %lu/%lu",
6888 + bytes_to_flush, packet_stream_id,
6889 + channel->local.id, channel->remote.id);
6891 + /* It's one of the streams we wanted to flush */
6892 + channel->flush_refund_bytes += packet->data_len - 13;
6893 + channel->flush_flush_bytes += bytes_to_flush;
6895 + LIBSSH2_FREE(channel->session, packet->data);
6896 + if (packet->prev) {
6897 + packet->prev->next = packet->next;
6899 + channel->session->packets.head = packet->next;
6901 + if (packet->next) {
6902 + packet->next->prev = packet->prev;
6904 + channel->session->packets.tail = packet->prev;
6906 + LIBSSH2_FREE(channel->session, packet);
6912 + channel->flush_state = libssh2_NB_state_created;
6915 + if (channel->flush_refund_bytes) {
6918 + rc = libssh2_channel_receive_window_adjust(channel,
6919 + channel->flush_refund_bytes,
6921 + if (rc == PACKET_EAGAIN) {
6922 + return PACKET_EAGAIN;
6926 + channel->flush_state = libssh2_NB_state_idle;
6928 + return channel->flush_flush_bytes;
6933 +/* {{{ libssh2_channel_get_exit_status
6934 + * Return the channel's program exit status
6937 +libssh2_channel_get_exit_status(LIBSSH2_CHANNEL * channel)
6939 + return channel->exit_status;
6944 +/* {{{ libssh2_channel_receive_window_adjust
6945 + * Adjust the receive window for a channel by adjustment bytes
6946 + * If the amount to be adjusted is less than LIBSSH2_CHANNEL_MINADJUST and
6947 + * force is 0 the adjustment amount will be queued for a later packet
6949 + * Returns the new size of the receive window (as understood by remote end)
6951 +LIBSSH2_API unsigned long
6952 +libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL * channel,
6953 + unsigned long adjustment,
6954 + unsigned char force)
6958 + if (channel->adjust_state == libssh2_NB_state_idle) {
6960 + && (adjustment + channel->adjust_queue <
6961 + LIBSSH2_CHANNEL_MINADJUST)) {
6962 + _libssh2_debug(channel->session, LIBSSH2_DBG_CONN,
6963 + "Queueing %lu bytes for receive window adjustment "
6964 + "for channel %lu/%lu",
6965 + adjustment, channel->local.id, channel->remote.id);
6966 + channel->adjust_queue += adjustment;
6967 + return channel->remote.window_size;
6970 + if (!adjustment && !channel->adjust_queue) {
6971 + return channel->remote.window_size;
6974 + adjustment += channel->adjust_queue;
6975 + channel->adjust_queue = 0;
6978 + /* Adjust the window based on the block we just freed */
6979 + channel->adjust_adjust[0] = SSH_MSG_CHANNEL_WINDOW_ADJUST;
6980 + libssh2_htonu32(channel->adjust_adjust + 1, channel->remote.id);
6981 + libssh2_htonu32(channel->adjust_adjust + 5, adjustment);
6982 + _libssh2_debug(channel->session, LIBSSH2_DBG_CONN,
6983 + "Adjusting window %lu bytes for data flushed from "
6984 + "channel %lu/%lu",
6985 + adjustment, channel->local.id, channel->remote.id);
6987 + channel->adjust_state = libssh2_NB_state_created;
6990 + rc = libssh2_packet_write(channel->session, channel->adjust_adjust, 9);
6991 + if (rc == PACKET_EAGAIN) {
6992 + return PACKET_EAGAIN;
6994 + libssh2_error(channel->session, LIBSSH2_ERROR_SOCKET_SEND,
6995 + "Unable to send transfer-window adjustment packet, "
6998 + channel->adjust_queue = adjustment;
6999 + channel->adjust_state = libssh2_NB_state_idle;
7001 + channel->adjust_state = libssh2_NB_state_idle;
7002 + channel->remote.window_size += adjustment;
7005 + return channel->remote.window_size;
7010 +/* {{{ libssh2_channel_handle_extended_data
7012 + * How should extended data look to the calling app? Keep it in separate
7013 + * channels[_read() _read_stdder()]? (NORMAL) Merge the extended data to the
7014 + * standard data? [everything via _read()]? (MERGE) Ignore it entirely [toss
7015 + * out packets as they come in]? (IGNORE)
7018 +libssh2_channel_handle_extended_data(LIBSSH2_CHANNEL * channel,
7021 + while (libssh2_channel_handle_extended_data2(channel, ignore_mode) ==
7026 +libssh2_channel_handle_extended_data2(LIBSSH2_CHANNEL * channel,
7029 + if (channel->extData2_state == libssh2_NB_state_idle) {
7030 + _libssh2_debug(channel->session, LIBSSH2_DBG_CONN,
7031 + "Setting channel %lu/%lu handle_extended_data mode to %d",
7032 + channel->local.id, channel->remote.id, ignore_mode);
7033 + channel->remote.extended_data_ignore_mode = ignore_mode;
7035 + channel->extData2_state = libssh2_NB_state_created;
7038 + if (channel->extData2_state == libssh2_NB_state_idle) {
7039 + if (ignore_mode == LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE) {
7040 + if (libssh2_channel_flush_ex
7042 + LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA) == PACKET_EAGAIN) {
7043 + return PACKET_EAGAIN;
7048 + channel->extData2_state = libssh2_NB_state_idle;
7055 + * {{{ libssh2_channel_read_ex
7056 + * Read data from a channel blocking or non-blocking depending on set state
7058 + * When this is done non-blocking, it is important to not return 0 until the
7059 + * currently read channel is complete. If we read stuff from the wire but it
7060 + * was no payload data to fill in the buffer with, we MUST make sure to return
7063 +LIBSSH2_API ssize_t
7064 +libssh2_channel_read_ex(LIBSSH2_CHANNEL * channel, int stream_id, char *buf,
7067 + LIBSSH2_SESSION *session = channel->session;
7068 + libssh2pack_t rc = 0;
7070 + if (channel->read_state == libssh2_NB_state_idle) {
7071 + _libssh2_debug(session, LIBSSH2_DBG_CONN,
7072 + "Attempting to read %d bytes from channel %lu/%lu stream #%d",
7073 + (int) buflen, channel->local.id, channel->remote.id,
7076 + /* process all incoming packets */
7078 + if (libssh2_waitsocket(session, 0) > 0) {
7079 + rc = libssh2_packet_read(session);
7081 + /* Set for PACKET_EAGAIN so we continue */
7082 + rc = PACKET_EAGAIN;
7086 + if ((rc < 0) && (rc != PACKET_EAGAIN)) {
7089 + channel->read_bytes_read = 0;
7091 + channel->read_packet = session->packets.head;
7092 + channel->read_state = libssh2_NB_state_created;
7096 + * =============================== NOTE ===============================
7097 + * I know this is very ugly and not a really good use of "goto", but
7098 + * this case statement would be even uglier to do it any other way
7100 + if (channel->read_state == libssh2_NB_state_jump1) {
7101 + goto channel_read_ex_point1;
7105 + channel->read_block = 0;
7108 + if (channel->read_block) {
7109 + /* in the second lap and onwards, do this...
7110 + * If we haven't yet filled our buffer, try to read more
7112 + if ( channel->read_bytes_read < (int) buflen) {
7113 + rc = libssh2_packet_read(session);
7115 + /* If we didn't find any more data to read */
7117 + if ( channel->read_bytes_read > 0){
7118 + break; /* finish processing and return */
7121 + /* no packets available, no data read. */
7122 + channel->read_state = libssh2_NB_state_idle;
7125 + /* We read more data, restart our processing at the beginning
7126 + * of our packet list. */
7127 + channel->read_packet = session->packets.head;
7129 + else { /* The read buffer is full, finish processing and return */
7134 + while (channel->read_packet
7135 + && (channel->read_bytes_read < (int) buflen)) {
7136 + /* In case packet gets destroyed during this iteration */
7137 + channel->read_next = channel->read_packet->next;
7139 + channel->read_local_id =
7140 + libssh2_ntohu32(channel->read_packet->data + 1);
7143 + * Either we asked for a specific extended data stream
7144 + * (and data was available),
7145 + * or the standard stream (and data was available),
7146 + * or the standard stream with extended_data_merge
7147 + * enabled and data was available
7150 + && (channel->read_packet->data[0] ==
7151 + SSH_MSG_CHANNEL_EXTENDED_DATA)
7152 + && (channel->local.id == channel->read_local_id)
7154 + (int) libssh2_ntohu32(channel->read_packet->data + 5)))
7156 + && (channel->read_packet->data[0] == SSH_MSG_CHANNEL_DATA)
7157 + && (channel->local.id == channel->read_local_id))
7159 + && (channel->read_packet->data[0] ==
7160 + SSH_MSG_CHANNEL_EXTENDED_DATA)
7161 + && (channel->local.id == channel->read_local_id)
7162 + && (channel->remote.extended_data_ignore_mode ==
7163 + LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE))) {
7165 + channel->read_want = buflen - channel->read_bytes_read;
7166 + channel->read_unlink_packet = 0;
7168 + if (channel->read_want >=
7169 + (int) (channel->read_packet->data_len -
7170 + channel->read_packet->data_head)) {
7171 + channel->read_want =
7172 + channel->read_packet->data_len -
7173 + channel->read_packet->data_head;
7174 + channel->read_unlink_packet = 1;
7177 + _libssh2_debug(session, LIBSSH2_DBG_CONN,
7178 + "Reading %d of buffered data from %lu/%lu/%d",
7179 + channel->read_want, channel->local.id,
7180 + channel->remote.id, stream_id);
7181 + memcpy(buf + channel->read_bytes_read,
7182 + channel->read_packet->data +
7183 + channel->read_packet->data_head, channel->read_want);
7184 + channel->read_packet->data_head += channel->read_want;
7185 + channel->read_bytes_read += channel->read_want;
7187 + if (channel->read_unlink_packet) {
7188 + if (channel->read_packet->prev) {
7189 + channel->read_packet->prev->next =
7190 + channel->read_packet->next;
7192 + session->packets.head = channel->read_packet->next;
7194 + if (channel->read_packet->next) {
7195 + channel->read_packet->next->prev =
7196 + channel->read_packet->prev;
7198 + session->packets.tail = channel->read_packet->prev;
7200 + LIBSSH2_FREE(session, channel->read_packet->data);
7203 + _libssh2_debug(session, LIBSSH2_DBG_CONN,
7204 + "Unlinking empty packet buffer from "
7205 + "channel %lu/%lu",
7206 + channel->local.id, channel->remote.id);
7207 + channel_read_ex_point1:
7208 + channel->read_state = libssh2_NB_state_jump1;
7209 + rc = libssh2_channel_receive_window_adjust(channel,
7215 + if (rc == PACKET_EAGAIN) {
7216 + return PACKET_EAGAIN;
7218 + channel->read_state = libssh2_NB_state_created;
7219 + LIBSSH2_FREE(session, channel->read_packet);
7220 + channel->read_packet = NULL;
7223 + channel->read_packet = channel->read_next;
7225 + channel->read_block = 1;
7226 + } while ((channel->read_bytes_read == 0) && !channel->remote.close);
7228 + channel->read_state = libssh2_NB_state_idle;
7229 + if (channel->read_bytes_read == 0) {
7230 + if (channel->session->socket_block) {
7231 + libssh2_error(session, LIBSSH2_ERROR_CHANNEL_CLOSED,
7232 + "Remote end has closed this channel", 0);
7235 + * when non-blocking, we must return PACKET_EAGAIN if we haven't
7236 + * completed reading the channel
7238 + if (!libssh2_channel_eof(channel)) {
7239 + return PACKET_EAGAIN;
7244 + channel->read_state = libssh2_NB_state_idle;
7245 + return channel->read_bytes_read;
7251 + * {{{ libssh2_channel_packet_data_len
7252 + * Return the size of the data block of the current packet, or 0 if there
7256 +libssh2_channel_packet_data_len(LIBSSH2_CHANNEL * channel, int stream_id)
7258 + LIBSSH2_SESSION *session = channel->session;
7259 + LIBSSH2_PACKET *read_packet;
7260 + uint32_t read_local_id;
7262 + if ((read_packet = session->packets.head) == NULL) {
7266 + while (read_packet) {
7267 + read_local_id = libssh2_ntohu32(read_packet->data + 1);
7270 + * Either we asked for a specific extended data stream
7271 + * (and data was available),
7272 + * or the standard stream (and data was available),
7273 + * or the standard stream with extended_data_merge
7274 + * enabled and data was available
7277 + && (read_packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA)
7278 + && (channel->local.id == read_local_id)
7279 + && (stream_id == (int) libssh2_ntohu32(read_packet->data + 5)))
7280 + || (!stream_id && (read_packet->data[0] == SSH_MSG_CHANNEL_DATA)
7281 + && (channel->local.id == read_local_id)) ||
7285 + SSH_MSG_CHANNEL_EXTENDED_DATA)
7291 + extended_data_ignore_mode
7293 + LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE)))
7295 + return (read_packet->data_len - read_packet->data_head);
7297 + read_packet = read_packet->next;
7305 +/* {{{ libssh2_channel_write_ex
7306 + * Send data to a channel
7308 +LIBSSH2_API ssize_t
7309 +libssh2_channel_write_ex(LIBSSH2_CHANNEL * channel, int stream_id,
7310 + const char *buf, size_t buflen)
7312 + LIBSSH2_SESSION *session = channel->session;
7315 + if (channel->write_state == libssh2_NB_state_idle) {
7316 + channel->write_bufwrote = 0;
7318 + _libssh2_debug(session, LIBSSH2_DBG_CONN,
7319 + "Writing %d bytes on channel %lu/%lu, stream #%d",
7320 + (int) buflen, channel->local.id, channel->remote.id,
7323 + if (channel->local.close) {
7324 + libssh2_error(session, LIBSSH2_ERROR_CHANNEL_CLOSED,
7325 + "We've already closed this channel", 0);
7329 + if (channel->local.eof) {
7330 + libssh2_error(session, LIBSSH2_ERROR_CHANNEL_EOF_SENT,
7331 + "EOF has already been sight, data might be ignored",
7335 + /* [13] 9 = packet_type(1) + channelno(4) [ + streamid(4) ] +
7337 + channel->write_packet_len = buflen + (stream_id ? 13 : 9);
7338 + channel->write_packet =
7339 + LIBSSH2_ALLOC(session, channel->write_packet_len);
7340 + if (!channel->write_packet) {
7341 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
7342 + "Unable to allocte space for data transmission packet",
7347 + channel->write_state = libssh2_NB_state_allocated;
7350 + while (buflen > 0) {
7351 + if (channel->write_state == libssh2_NB_state_allocated) {
7352 + channel->write_bufwrite = buflen;
7353 + channel->write_s = channel->write_packet;
7355 + *(channel->write_s++) =
7356 + stream_id ? SSH_MSG_CHANNEL_EXTENDED_DATA :
7357 + SSH_MSG_CHANNEL_DATA;
7358 + libssh2_htonu32(channel->write_s, channel->remote.id);
7359 + channel->write_s += 4;
7361 + libssh2_htonu32(channel->write_s, stream_id);
7362 + channel->write_s += 4;
7365 + /* twiddle our thumbs until there's window space available */
7366 + while (channel->local.window_size <= 0) {
7367 + /* Don't worry -- This is never hit unless it's a
7368 + blocking channel anyway */
7369 + rc = libssh2_packet_read(session);
7372 + /* Error or EAGAIN occurred, disconnect? */
7373 + if (rc != PACKET_EAGAIN) {
7374 + channel->write_state = libssh2_NB_state_idle;
7379 + if ((rc == 0) && (session->socket_block == 0)) {
7381 + * if rc == 0 and in non-blocking, then fake EAGAIN
7382 + * to prevent busyloops until data arriaves on the network
7383 + * which seemed like a very bad idea
7385 + return PACKET_EAGAIN;
7389 + /* Don't exceed the remote end's limits */
7390 + /* REMEMBER local means local as the SOURCE of the data */
7391 + if (channel->write_bufwrite > channel->local.window_size) {
7392 + _libssh2_debug(session, LIBSSH2_DBG_CONN,
7393 + "Splitting write block due to %lu byte "
7394 + "window_size on %lu/%lu/%d",
7395 + channel->local.window_size, channel->local.id,
7396 + channel->remote.id, stream_id);
7397 + channel->write_bufwrite = channel->local.window_size;
7399 + if (channel->write_bufwrite > channel->local.packet_size) {
7400 + _libssh2_debug(session, LIBSSH2_DBG_CONN,
7401 + "Splitting write block due to %lu byte "
7402 + "packet_size on %lu/%lu/%d",
7403 + channel->local.packet_size, channel->local.id,
7404 + channel->remote.id, stream_id);
7405 + channel->write_bufwrite = channel->local.packet_size;
7407 + libssh2_htonu32(channel->write_s, channel->write_bufwrite);
7408 + channel->write_s += 4;
7409 + memcpy(channel->write_s, buf, channel->write_bufwrite);
7410 + channel->write_s += channel->write_bufwrite;
7412 + _libssh2_debug(session, LIBSSH2_DBG_CONN,
7413 + "Sending %d bytes on channel %lu/%lu, stream_id=%d",
7414 + (int) channel->write_bufwrite, channel->local.id,
7415 + channel->remote.id, stream_id);
7417 + channel->write_state = libssh2_NB_state_created;
7420 + if (channel->write_state == libssh2_NB_state_created) {
7421 + rc = libssh2_packet_write(session, channel->write_packet,
7422 + channel->write_s -
7423 + channel->write_packet);
7424 + if (rc == PACKET_EAGAIN) {
7425 + _libssh2_debug(session, LIBSSH2_DBG_CONN,
7426 + "libssh2_packet_write returned EAGAIN");
7427 + return PACKET_EAGAIN;
7430 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
7431 + "Unable to send channel data", 0);
7432 + LIBSSH2_FREE(session, channel->write_packet);
7433 + channel->write_packet = NULL;
7434 + channel->write_state = libssh2_NB_state_idle;
7437 + /* Shrink local window size */
7438 + channel->local.window_size -= channel->write_bufwrite;
7440 + /* Adjust buf for next iteration */
7441 + buflen -= channel->write_bufwrite;
7442 + buf += channel->write_bufwrite;
7443 + channel->write_bufwrote += channel->write_bufwrite;
7445 + channel->write_state = libssh2_NB_state_allocated;
7448 + * Not sure this is still wanted
7449 + if (!channel->session->socket_block) {
7456 + LIBSSH2_FREE(session, channel->write_packet);
7457 + channel->write_packet = NULL;
7459 + channel->write_state = libssh2_NB_state_idle;
7461 + return channel->write_bufwrote;
7466 +/* {{{ libssh2_channel_send_eof
7467 + * Send EOF on channel
7470 +libssh2_channel_send_eof(LIBSSH2_CHANNEL * channel)
7472 + LIBSSH2_SESSION *session = channel->session;
7473 + unsigned char packet[5]; /* packet_type(1) + channelno(4) */
7476 + _libssh2_debug(session, LIBSSH2_DBG_CONN, "Sending EOF on channel %lu/%lu",
7477 + channel->local.id, channel->remote.id);
7478 + packet[0] = SSH_MSG_CHANNEL_EOF;
7479 + libssh2_htonu32(packet + 1, channel->remote.id);
7480 + rc = libssh2_packet_write(session, packet, 5);
7481 + if (rc == PACKET_EAGAIN) {
7482 + return PACKET_EAGAIN;
7484 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
7485 + "Unable to send EOF on channel", 0);
7488 + channel->local.eof = 1;
7495 +/* {{{ libssh2_channel_eof
7496 + * Read channel's eof status
7499 +libssh2_channel_eof(LIBSSH2_CHANNEL * channel)
7501 + LIBSSH2_SESSION *session = channel->session;
7502 + LIBSSH2_PACKET *packet = session->packets.head;
7505 + if (((packet->data[0] == SSH_MSG_CHANNEL_DATA)
7506 + || (packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA))
7507 + && (channel->local.id == libssh2_ntohu32(packet->data + 1))) {
7508 + /* There's data waiting to be read yet, mask the EOF status */
7511 + packet = packet->next;
7514 + return channel->remote.eof;
7519 +/* {{{ libssh2_channel_wait_eof
7520 +* Awaiting channel EOF
7523 +libssh2_channel_wait_eof(LIBSSH2_CHANNEL * channel)
7525 + LIBSSH2_SESSION *session = channel->session;
7528 + if (channel->wait_eof_state == libssh2_NB_state_idle) {
7529 + _libssh2_debug(session, LIBSSH2_DBG_CONN,
7530 + "Awaiting close of channel %lu/%lu", channel->local.id,
7531 + channel->remote.id);
7533 + channel->wait_eof_state = libssh2_NB_state_created;
7537 + * While channel is not eof, read more packets from the network.
7538 + * Either the EOF will be set or network timeout will occur.
7541 + if (channel->remote.eof) {
7544 + rc = libssh2_packet_read(session);
7545 + if (rc == PACKET_EAGAIN) {
7546 + return PACKET_EAGAIN;
7547 + } else if (rc < 0) {
7548 + channel->wait_eof_state = libssh2_NB_state_idle;
7553 + channel->wait_eof_state = libssh2_NB_state_idle;
7561 +/* {{{ libssh2_channel_close
7565 +libssh2_channel_close(LIBSSH2_CHANNEL * channel)
7567 + LIBSSH2_SESSION *session = channel->session;
7571 + if (channel->local.close) {
7572 + /* Already closed, act like we sent another close,
7573 + * even though we didn't... shhhhhh */
7574 + channel->close_state = libssh2_NB_state_idle;
7578 + if (channel->close_state == libssh2_NB_state_idle) {
7579 + _libssh2_debug(session, LIBSSH2_DBG_CONN, "Closing channel %lu/%lu",
7580 + channel->local.id, channel->remote.id);
7582 + if (channel->close_cb) {
7583 + LIBSSH2_CHANNEL_CLOSE(session, channel);
7585 + channel->local.close = 1;
7587 + channel->close_packet[0] = SSH_MSG_CHANNEL_CLOSE;
7588 + libssh2_htonu32(channel->close_packet + 1, channel->remote.id);
7590 + channel->close_state = libssh2_NB_state_created;
7593 + if (channel->close_state == libssh2_NB_state_created) {
7594 + retcode = libssh2_packet_write(session, channel->close_packet, 5);
7595 + if (retcode == PACKET_EAGAIN) {
7596 + return PACKET_EAGAIN;
7597 + } else if (retcode) {
7598 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
7599 + "Unable to send close-channel request", 0);
7600 + channel->close_state = libssh2_NB_state_idle;
7604 + channel->close_state = libssh2_NB_state_sent;
7607 + if (channel->close_state == libssh2_NB_state_sent) {
7608 + /* We must wait for the remote SSH_MSG_CHANNEL_CLOSE message */
7609 + if (!channel->remote.close) {
7610 + libssh2pack_t ret;
7613 + ret = libssh2_packet_read(session);
7614 + if (ret == PACKET_EAGAIN) {
7615 + return PACKET_EAGAIN;
7616 + } else if (ret < 0) {
7619 + } while ((ret != SSH_MSG_CHANNEL_CLOSE) && (rc == 0));
7623 + channel->close_state = libssh2_NB_state_idle;
7630 +/* {{{ libssh2_channel_wait_closed
7631 + * Awaiting channel close after EOF
7634 +libssh2_channel_wait_closed(LIBSSH2_CHANNEL * channel)
7636 + LIBSSH2_SESSION *session = channel->session;
7639 + if (!libssh2_channel_eof(channel)) {
7640 + libssh2_error(session, LIBSSH2_ERROR_INVAL,
7641 + "libssh2_channel_wait_closed() invoked when channel is "
7642 + "not in EOF state",
7647 + if (channel->wait_closed_state == libssh2_NB_state_idle) {
7648 + _libssh2_debug(session, LIBSSH2_DBG_CONN,
7649 + "Awaiting close of channel %lu/%lu", channel->local.id,
7650 + channel->remote.id);
7652 + channel->wait_closed_state = libssh2_NB_state_created;
7656 + * While channel is not closed, read more packets from the network.
7657 + * Either the channel will be closed or network timeout will occur.
7660 + if (!channel->remote.close) {
7663 + rc = libssh2_packet_read(session);
7664 + if (rc == PACKET_EAGAIN) {
7665 + return PACKET_EAGAIN;
7666 + } else if (rc <= 0) {
7671 + channel->wait_closed_state = libssh2_NB_state_idle;
7679 +/* {{{ libssh2_channel_free
7680 + * Make sure a channel is closed, then remove the channel from the session
7681 + * and free its resource(s)
7683 + * Returns 0 on success, -1 on failure
7686 +libssh2_channel_free(LIBSSH2_CHANNEL * channel)
7688 + LIBSSH2_SESSION *session = channel->session;
7689 + unsigned char channel_id[4];
7690 + unsigned char *data;
7691 + unsigned long data_len;
7694 + if (channel->free_state == libssh2_NB_state_idle) {
7695 + _libssh2_debug(session, LIBSSH2_DBG_CONN,
7696 + "Freeing channel %lu/%lu resources", channel->local.id,
7697 + channel->remote.id);
7699 + channel->free_state = libssh2_NB_state_created;
7702 + /* Allow channel freeing even when the socket has lost its connection */
7703 + if (!channel->local.close
7704 + && (session->socket_state == LIBSSH2_SOCKET_CONNECTED)) {
7705 + while ((rc = libssh2_channel_close(channel)) == PACKET_EAGAIN);
7707 + channel->free_state = libssh2_NB_state_idle;
7712 + channel->free_state = libssh2_NB_state_idle;
7715 + * channel->remote.close *might* not be set yet, Well...
7716 + * We've sent the close packet, what more do you want?
7717 + * Just let packet_add ignore it when it finally arrives
7720 + /* Clear out packets meant for this channel */
7721 + libssh2_htonu32(channel_id, channel->local.id);
7722 + while ((libssh2_packet_ask_ex
7723 + (session, SSH_MSG_CHANNEL_DATA, &data, &data_len, 1, channel_id, 4,
7726 + (libssh2_packet_ask_ex
7727 + (session, SSH_MSG_CHANNEL_EXTENDED_DATA, &data, &data_len, 1,
7728 + channel_id, 4, 0) >= 0)) {
7729 + LIBSSH2_FREE(session, data);
7732 + /* free "channel_type" */
7733 + if (channel->channel_type) {
7734 + LIBSSH2_FREE(session, channel->channel_type);
7737 + /* Unlink from channel brigade */
7738 + if (channel->prev) {
7739 + channel->prev->next = channel->next;
7741 + session->channels.head = channel->next;
7743 + if (channel->next) {
7744 + channel->next->prev = channel->prev;
7746 + session->channels.tail = channel->prev;
7750 + * Make sure all memory used in the state variables are free
7752 + if (channel->setenv_packet) {
7753 + LIBSSH2_FREE(session, channel->setenv_packet);
7755 + if (channel->reqPTY_packet) {
7756 + LIBSSH2_FREE(session, channel->reqPTY_packet);
7758 + if (channel->reqX11_packet) {
7759 + LIBSSH2_FREE(session, channel->reqX11_packet);
7761 + if (channel->process_packet) {
7762 + LIBSSH2_FREE(session, channel->process_packet);
7764 + if (channel->write_packet) {
7765 + LIBSSH2_FREE(session, channel->write_packet);
7768 + LIBSSH2_FREE(session, channel);
7775 +/* {{{ libssh2_channel_window_read_ex
7777 + * Check the status of the read window. Returns the number of bytes which the
7778 + * remote end may send without overflowing the window limit read_avail (if
7779 + * passed) will be populated with the number of bytes actually available to be
7780 + * read window_size_initial (if passed) will be populated with the
7781 + * window_size_initial as defined by the channel_open request
7783 +LIBSSH2_API unsigned long
7784 +libssh2_channel_window_read_ex(LIBSSH2_CHANNEL * channel,
7785 + unsigned long *read_avail,
7786 + unsigned long *window_size_initial)
7788 + if (window_size_initial) {
7789 + *window_size_initial = channel->remote.window_size_initial;
7793 + unsigned long bytes_queued = 0;
7794 + LIBSSH2_PACKET *packet = channel->session->packets.head;
7797 + unsigned char packet_type = packet->data[0];
7799 + if (((packet_type == SSH_MSG_CHANNEL_DATA)
7800 + || (packet_type == SSH_MSG_CHANNEL_EXTENDED_DATA))
7801 + && (libssh2_ntohu32(packet->data + 1) == channel->local.id)) {
7802 + bytes_queued += packet->data_len - packet->data_head;
7805 + packet = packet->next;
7808 + *read_avail = bytes_queued;
7811 + return channel->remote.window_size;
7816 +/* {{{ libssh2_channel_window_write_ex
7818 + * Check the status of the write window Returns the number of bytes which may
7819 + * be safely writen on the channel without blocking window_size_initial (if
7820 + * passed) will be populated with the size of the initial window as defined by
7821 + * the channel_open request
7823 +LIBSSH2_API unsigned long
7824 +libssh2_channel_window_write_ex(LIBSSH2_CHANNEL * channel,
7825 + unsigned long *window_size_initial)
7827 + if (window_size_initial) {
7828 + /* For locally initiated channels this is very often 0, so it's not
7829 + * *that* useful as information goes */
7830 + *window_size_initial = channel->local.window_size_initial;
7833 + return channel->local.window_size;
7838 Property changes on: libssh2/src/channel.c
7839 ___________________________________________________________________
7840 Added: svn:mime-type
7843 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
7844 Added: cvs2svn:cvs-rev
7846 Added: svn:eol-style
7849 Index: libssh2/src/libssh2_priv.h
7850 ===================================================================
7851 --- libssh2/src/libssh2_priv.h (.../tags/RELEASE_0_11_0)
7852 +++ libssh2/src/libssh2_priv.h (.../trunk)
7854 +/* Copyright (c) 2004-2008, Sara Golemon <sarag@libssh2.org>
7855 + * All rights reserved.
7857 + * Redistribution and use in source and binary forms,
7858 + * with or without modification, are permitted provided
7859 + * that the following conditions are met:
7861 + * Redistributions of source code must retain the above
7862 + * copyright notice, this list of conditions and the
7863 + * following disclaimer.
7865 + * Redistributions in binary form must reproduce the above
7866 + * copyright notice, this list of conditions and the following
7867 + * disclaimer in the documentation and/or other materials
7868 + * provided with the distribution.
7870 + * Neither the name of the copyright holder nor the names
7871 + * of any other contributors may be used to endorse or
7872 + * promote products derived from this software without
7873 + * specific prior written permission.
7875 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
7876 + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
7877 + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
7878 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
7879 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
7880 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
7881 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
7882 + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
7883 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
7884 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
7885 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
7886 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
7887 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
7891 +#ifndef LIBSSH2_PRIV_H
7892 +#define LIBSSH2_PRIV_H 1
7894 +#define LIBSSH2_LIBRARY
7895 +#include "libssh2_config.h"
7897 +#ifdef HAVE_WINDOWS_H
7898 +#include <windows.h>
7901 +#ifdef HAVE_WS2TCPIP_H
7902 +#include <ws2tcpip.h>
7908 +/* The following CPP block should really only be in session.c and
7909 + packet.c. However, AIX have #define's for 'events' and 'revents'
7910 + and we are using those names in libssh2.h, so we need to include
7911 + the AIX headers first, to make sure all code is compiled with
7912 + consistent names of these fields. While arguable the best would to
7913 + change libssh2.h to use other names, that would break backwards
7914 + compatibility. For more information, see:
7915 + http://www.mail-archive.com/libssh2-devel%40lists.sourceforge.net/msg00003.html
7916 + http://www.mail-archive.com/libssh2-devel%40lists.sourceforge.net/msg00224.html
7919 +# include <sys/poll.h>
7921 +# if defined(HAVE_SELECT) && !defined(WIN32)
7922 +# ifdef HAVE_SYS_SELECT_H
7923 +# include <sys/select.h>
7925 +# include <sys/time.h>
7926 +# include <sys/types.h>
7931 +#include "libssh2.h"
7932 +#include "libssh2_publickey.h"
7933 +#include "libssh2_sftp.h"
7935 +/* Provide iovec / writev on WIN32 platform. */
7938 +/* same as WSABUF */
7944 +#define inline __inline
7946 +static inline int writev(int sock, struct iovec *iov, int nvecs)
7949 + if (WSASend(sock, (LPWSABUF)iov, nvecs, &ret, 0, NULL, NULL) == 0) {
7957 +/* Needed for struct iovec on some platforms */
7958 +#ifdef HAVE_SYS_UIO_H
7959 +#include <sys/uio.h>
7962 +#ifdef HAVE_SYS_SOCKET_H
7963 +# include <sys/socket.h>
7965 +#ifdef HAVE_SYS_IOCTL_H
7966 +# include <sys/ioctl.h>
7968 +#ifdef HAVE_INTTYPES_H
7969 +#include <inttypes.h>
7972 +#ifdef LIBSSH2_LIBGCRYPT
7973 +#include "libgcrypt.h"
7975 +#include "openssl.h"
7978 +#ifdef HAVE_WINSOCK2_H
7980 +#include <winsock2.h>
7981 +#include <mswsock.h>
7982 +#include <ws2tcpip.h>
7985 +/* "inline" keyword is valid only with C++ engine! */
7986 +#define inline __inline
7989 +/* not really usleep, but safe for the way we use it in this lib */
7990 +static inline int usleep(int udelay)
7992 + Sleep(udelay / 1000);
7998 +/* RFC4253 section 6.1 Maximum Packet Length says:
8000 + * "All implementations MUST be able to process packets with
8001 + * uncompressed payload length of 32768 bytes or less and
8002 + * total packet size of 35000 bytes or less (including length,
8003 + * padding length, payload, padding, and MAC.)."
8005 +#define MAX_SSH_PACKET_LEN 35000
8007 +#define LIBSSH2_ALLOC(session, count) session->alloc((count), &(session)->abstract)
8008 +#define LIBSSH2_REALLOC(session, ptr, count) ((ptr) ? session->realloc((ptr), (count), &(session)->abstract) : session->alloc((count), &(session)->abstract))
8009 +#define LIBSSH2_FREE(session, ptr) session->free((ptr), &(session)->abstract)
8011 +#define LIBSSH2_IGNORE(session, data, datalen) session->ssh_msg_ignore((session), (data), (datalen), &(session)->abstract)
8012 +#define LIBSSH2_DEBUG(session, always_display, message, message_len, language, language_len) \
8013 + session->ssh_msg_disconnect((session), (always_display), (message), (message_len), (language), (language_len), &(session)->abstract)
8014 +#define LIBSSH2_DISCONNECT(session, reason, message, message_len, language, language_len) \
8015 + session->ssh_msg_disconnect((session), (reason), (message), (message_len), (language), (language_len), &(session)->abstract)
8017 +#define LIBSSH2_MACERROR(session, data, datalen) session->macerror((session), (data), (datalen), &(session)->abstract)
8018 +#define LIBSSH2_X11_OPEN(channel, shost, sport) channel->session->x11(((channel)->session), (channel), (shost), (sport), (&(channel)->session->abstract))
8020 +#define LIBSSH2_CHANNEL_CLOSE(session, channel) channel->close_cb((session), &(session)->abstract, (channel), &(channel)->abstract)
8022 +typedef struct _LIBSSH2_KEX_METHOD LIBSSH2_KEX_METHOD;
8023 +typedef struct _LIBSSH2_HOSTKEY_METHOD LIBSSH2_HOSTKEY_METHOD;
8024 +typedef struct _LIBSSH2_MAC_METHOD LIBSSH2_MAC_METHOD;
8025 +typedef struct _LIBSSH2_CRYPT_METHOD LIBSSH2_CRYPT_METHOD;
8026 +typedef struct _LIBSSH2_COMP_METHOD LIBSSH2_COMP_METHOD;
8028 +typedef struct _LIBSSH2_PACKET LIBSSH2_PACKET;
8029 +typedef struct _LIBSSH2_PACKET_BRIGADE LIBSSH2_PACKET_BRIGADE;
8030 +typedef struct _LIBSSH2_CHANNEL_BRIGADE LIBSSH2_CHANNEL_BRIGADE;
8032 +typedef int libssh2pack_t;
8036 + libssh2_NB_state_idle = 0,
8037 + libssh2_NB_state_allocated,
8038 + libssh2_NB_state_created,
8039 + libssh2_NB_state_sent,
8040 + libssh2_NB_state_sent1,
8041 + libssh2_NB_state_sent2,
8042 + libssh2_NB_state_sent3,
8043 + libssh2_NB_state_sent4,
8044 + libssh2_NB_state_sent5,
8045 + libssh2_NB_state_sent6,
8046 + libssh2_NB_state_sent7,
8047 + libssh2_NB_state_jump1,
8048 + libssh2_NB_state_jump2,
8049 + libssh2_NB_state_jump3
8050 +} libssh2_nonblocking_states;
8052 +typedef struct packet_require_state_t
8054 + libssh2_nonblocking_states state;
8056 +} packet_require_state_t;
8058 +typedef struct packet_requirev_state_t
8061 +} packet_requirev_state_t;
8063 +typedef struct kmdhgGPsha1kex_state_t
8065 + libssh2_nonblocking_states state;
8066 + unsigned char *e_packet;
8067 + unsigned char *s_packet;
8068 + unsigned char *tmp;
8069 + unsigned char h_sig_comp[SHA_DIGEST_LENGTH];
8071 + unsigned long e_packet_len;
8072 + unsigned long s_packet_len;
8073 + unsigned long tmp_len;
8074 + _libssh2_bn_ctx *ctx;
8080 + unsigned char *f_value;
8081 + unsigned char *k_value;
8082 + unsigned char *h_sig;
8083 + unsigned long f_value_len;
8084 + unsigned long k_value_len;
8085 + unsigned long h_sig_len;
8086 + libssh2_sha1_ctx exchange_hash;
8087 + packet_require_state_t req_state;
8088 + libssh2_nonblocking_states burn_state;
8089 +} kmdhgGPsha1kex_state_t;
8091 +typedef struct key_exchange_state_low_t
8093 + libssh2_nonblocking_states state;
8094 + packet_require_state_t req_state;
8095 + kmdhgGPsha1kex_state_t exchange_state;
8096 + _libssh2_bn *p; /* SSH2 defined value (p_value) */
8097 + _libssh2_bn *g; /* SSH2 defined value (2) */
8098 + unsigned char request[13];
8099 + unsigned char *data;
8100 + unsigned long request_len;
8101 + unsigned long data_len;
8102 +} key_exchange_state_low_t;
8104 +typedef struct key_exchange_state_t
8106 + libssh2_nonblocking_states state;
8107 + packet_require_state_t req_state;
8108 + key_exchange_state_low_t key_state_low;
8109 + unsigned char *data;
8110 + unsigned long data_len;
8111 + unsigned char *oldlocal;
8112 + unsigned long oldlocal_len;
8113 +} key_exchange_state_t;
8115 +#define FwdNotReq "Forward not requested"
8117 +typedef struct packet_queue_listener_state_t
8119 + libssh2_nonblocking_states state;
8120 + unsigned char packet[17 + (sizeof(FwdNotReq) - 1)];
8121 + unsigned char *host;
8122 + unsigned char *shost;
8123 + uint32_t sender_channel;
8124 + uint32_t initial_window_size;
8125 + uint32_t packet_size;
8128 + uint32_t host_len;
8129 + uint32_t shost_len;
8130 +} packet_queue_listener_state_t;
8132 +#define X11FwdUnAvil "X11 Forward Unavailable"
8134 +typedef struct packet_x11_open_state_t
8136 + libssh2_nonblocking_states state;
8137 + unsigned char packet[17 + (sizeof(X11FwdUnAvil) - 1)];
8138 + unsigned char *shost;
8139 + uint32_t sender_channel;
8140 + uint32_t initial_window_size;
8141 + uint32_t packet_size;
8143 + uint32_t shost_len;
8144 +} packet_x11_open_state_t;
8146 +struct _LIBSSH2_PACKET
8148 + unsigned char type;
8150 + /* Unencrypted Payload (no type byte, no padding, just the facts ma'am) */
8151 + unsigned char *data;
8152 + unsigned long data_len;
8154 + /* Where to start reading data from,
8155 + * used for channel data that's been partially consumed */
8156 + unsigned long data_head;
8158 + /* Can the message be confirmed? */
8161 + LIBSSH2_PACKET_BRIGADE *brigade;
8163 + LIBSSH2_PACKET *next, *prev;
8166 +struct _LIBSSH2_PACKET_BRIGADE
8168 + LIBSSH2_PACKET *head, *tail;
8171 +typedef struct _libssh2_channel_data
8176 + /* Limits and restrictions */
8177 + unsigned long window_size_initial, window_size, packet_size;
8179 + /* Set to 1 when CHANNEL_CLOSE / CHANNEL_EOF sent/received */
8180 + char close, eof, extended_data_ignore_mode;
8181 +} libssh2_channel_data;
8183 +struct _LIBSSH2_CHANNEL
8185 + unsigned char *channel_type;
8186 + unsigned channel_type_len;
8188 + /* channel's program exit status */
8191 + libssh2_channel_data local, remote;
8192 + /* Amount of bytes to be refunded to receive window (but not yet sent) */
8193 + unsigned long adjust_queue;
8195 + LIBSSH2_SESSION *session;
8197 + LIBSSH2_CHANNEL *next, *prev;
8200 + LIBSSH2_CHANNEL_CLOSE_FUNC((*close_cb));
8202 + /* State variables used in libssh2_channel_setenv_ex() */
8203 + libssh2_nonblocking_states setenv_state;
8204 + unsigned char *setenv_packet;
8205 + unsigned long setenv_packet_len;
8206 + unsigned char setenv_local_channel[4];
8207 + packet_requirev_state_t setenv_packet_requirev_state;
8209 + /* State variables used in libssh2_channel_request_pty_ex() */
8210 + libssh2_nonblocking_states reqPTY_state;
8211 + unsigned char *reqPTY_packet;
8212 + unsigned long reqPTY_packet_len;
8213 + unsigned char reqPTY_local_channel[4];
8214 + packet_requirev_state_t reqPTY_packet_requirev_state;
8216 + /* State variables used in libssh2_channel_x11_req_ex() */
8217 + libssh2_nonblocking_states reqX11_state;
8218 + unsigned char *reqX11_packet;
8219 + unsigned long reqX11_packet_len;
8220 + unsigned char reqX11_local_channel[4];
8221 + packet_requirev_state_t reqX11_packet_requirev_state;
8223 + /* State variables used in libssh2_channel_process_startup() */
8224 + libssh2_nonblocking_states process_state;
8225 + unsigned char *process_packet;
8226 + unsigned long process_packet_len;
8227 + unsigned char process_local_channel[4];
8228 + packet_requirev_state_t process_packet_requirev_state;
8230 + /* State variables used in libssh2_channel_flush_ex() */
8231 + libssh2_nonblocking_states flush_state;
8232 + unsigned long flush_refund_bytes;
8233 + unsigned long flush_flush_bytes;
8235 + /* State variables used in libssh2_channel_receive_window_adjust() */
8236 + libssh2_nonblocking_states adjust_state;
8237 + unsigned char adjust_adjust[9]; /* packet_type(1) + channel(4) + adjustment(4) */
8239 + /* State variables used in libssh2_channel_read_ex() */
8240 + libssh2_nonblocking_states read_state;
8241 + LIBSSH2_PACKET *read_packet;
8242 + LIBSSH2_PACKET *read_next;
8244 + int read_bytes_read;
8245 + uint32_t read_local_id;
8247 + int read_unlink_packet;
8249 + /* State variables used in libssh2_channel_write_ex() */
8250 + libssh2_nonblocking_states write_state;
8251 + unsigned char *write_packet;
8252 + unsigned char *write_s;
8253 + unsigned long write_packet_len;
8254 + unsigned long write_bufwrote;
8255 + size_t write_bufwrite;
8257 + /* State variables used in libssh2_channel_close() */
8258 + libssh2_nonblocking_states close_state;
8259 + unsigned char close_packet[5];
8261 + /* State variables used in libssh2_channel_wait_closedeof() */
8262 + libssh2_nonblocking_states wait_eof_state;
8264 + /* State variables used in libssh2_channel_wait_closed() */
8265 + libssh2_nonblocking_states wait_closed_state;
8267 + /* State variables used in libssh2_channel_free() */
8268 + libssh2_nonblocking_states free_state;
8270 + /* State variables used in libssh2_channel_handle_extended_data2() */
8271 + libssh2_nonblocking_states extData2_state;
8274 +struct _LIBSSH2_CHANNEL_BRIGADE
8276 + LIBSSH2_CHANNEL *head, *tail;
8279 +struct _LIBSSH2_LISTENER
8281 + LIBSSH2_SESSION *session;
8286 + LIBSSH2_CHANNEL *queue;
8288 + int queue_maxsize;
8290 + LIBSSH2_LISTENER *prev, *next;
8292 + /* State variables used in libssh2_channel_forward_cancel() */
8293 + libssh2_nonblocking_states chanFwdCncl_state;
8294 + unsigned char *chanFwdCncl_data;
8295 + size_t chanFwdCncl_data_len;
8298 +typedef struct _libssh2_endpoint_data
8300 + unsigned char *banner;
8302 + unsigned char *kexinit;
8303 + unsigned long kexinit_len;
8305 + const LIBSSH2_CRYPT_METHOD *crypt;
8306 + void *crypt_abstract;
8308 + const LIBSSH2_MAC_METHOD *mac;
8309 + unsigned long seqno;
8310 + void *mac_abstract;
8312 + const LIBSSH2_COMP_METHOD *comp;
8313 + void *comp_abstract;
8315 + /* Method Preferences -- NULL yields "load order" */
8316 + char *crypt_prefs;
8320 +} libssh2_endpoint_data;
8322 +#define PACKETBUFSIZE 4096
8324 +struct transportpacket
8326 + /* ------------- for incoming data --------------- */
8327 + unsigned char buf[PACKETBUFSIZE];
8328 + unsigned char init[5]; /* first 5 bytes of the incoming data stream,
8329 + still encrypted */
8330 + int writeidx; /* at what array index we do the next write into
8332 + int readidx; /* at what array index we do the next read from
8334 + int packet_length; /* the most recent packet_length as read from the
8336 + int padding_length; /* the most recent padding_length as read from the
8338 + int data_num; /* How much of the total package that has been read
8340 + int total_num; /* How much a total package is supposed to be, in
8341 + number of bytes. A full package is
8342 + packet_length + padding_length + 4 +
8344 + unsigned char *payload; /* this is a pointer to a LIBSSH2_ALLOC()
8345 + area to which we write decrypted data */
8346 + unsigned char *wptr; /* write pointer into the payload to where we
8347 + are currently writing decrypted data */
8349 + /* ------------- for outgoing data --------------- */
8350 + unsigned char *outbuf; /* pointer to a LIBSSH2_ALLOC() area for the
8352 + int ototal_num; /* size of outbuf in number of bytes */
8353 + unsigned char *odata; /* original pointer to the data we stored in
8355 + unsigned long olen; /* original size of the data we stored in
8357 + unsigned long osent; /* number of bytes already sent */
8360 +struct _LIBSSH2_PUBLICKEY
8362 + LIBSSH2_CHANNEL *channel;
8363 + unsigned long version;
8365 + /* State variables used in libssh2_publickey_packet_receive() */
8366 + libssh2_nonblocking_states receive_state;
8367 + unsigned char *receive_packet;
8368 + unsigned long receive_packet_len;
8370 + /* State variables used in libssh2_publickey_add_ex() */
8371 + libssh2_nonblocking_states add_state;
8372 + unsigned char *add_packet;
8373 + unsigned char *add_s;
8375 + /* State variables used in libssh2_publickey_remove_ex() */
8376 + libssh2_nonblocking_states remove_state;
8377 + unsigned char *remove_packet;
8378 + unsigned char *remove_s;
8380 + /* State variables used in libssh2_publickey_list_fetch() */
8381 + libssh2_nonblocking_states listFetch_state;
8382 + unsigned char *listFetch_s;
8383 + unsigned char listFetch_buffer[12];
8384 + unsigned char *listFetch_data;
8385 + unsigned long listFetch_data_len;
8388 +#define SFTP_HANDLE_MAXLEN 256 /* according to spec! */
8390 +struct _LIBSSH2_SFTP_HANDLE
8392 + LIBSSH2_SFTP *sftp;
8393 + LIBSSH2_SFTP_HANDLE *prev, *next;
8395 + /* This is a pre-allocated buffer used for sending SFTP requests as the
8396 + whole thing might not get sent in one go. This buffer is used for read,
8397 + write, close and MUST thus be big enough to suit all these. */
8398 + unsigned char request_packet[SFTP_HANDLE_MAXLEN + 25];
8400 + char handle[SFTP_HANDLE_MAXLEN];
8405 + union _libssh2_sftp_handle_data
8407 + struct _libssh2_sftp_handle_file_data
8409 + libssh2_uint64_t offset;
8411 + struct _libssh2_sftp_handle_dir_data
8413 + unsigned long names_left;
8414 + void *names_packet;
8419 + /* State variables used in libssh2_sftp_close_handle() */
8420 + libssh2_nonblocking_states close_state;
8421 + unsigned long close_request_id;
8422 + unsigned char *close_packet;
8425 +struct _LIBSSH2_SFTP
8427 + LIBSSH2_CHANNEL *channel;
8429 + unsigned long request_id, version;
8431 + LIBSSH2_PACKET_BRIGADE packets;
8433 + LIBSSH2_SFTP_HANDLE *handles;
8435 + unsigned long last_errno;
8437 + /* Holder for partial packet, use in libssh2_sftp_packet_read() */
8438 + unsigned char *partial_packet; /* The data */
8439 + unsigned long partial_len; /* Desired number of bytes */
8440 + unsigned long partial_received; /* Bytes received so far */
8442 + /* Time that libssh2_sftp_packet_requirev() started reading */
8443 + time_t requirev_start;
8445 + /* State variables used in libssh2_sftp_open_ex() */
8446 + libssh2_nonblocking_states open_state;
8447 + unsigned char *open_packet;
8448 + ssize_t open_packet_len;
8449 + unsigned long open_request_id;
8451 + /* State variables used in libssh2_sftp_read() */
8452 + libssh2_nonblocking_states read_state;
8453 + unsigned char *read_packet;
8454 + unsigned long read_request_id;
8455 + size_t read_total_read;
8457 + /* State variables used in libssh2_sftp_readdir() */
8458 + libssh2_nonblocking_states readdir_state;
8459 + unsigned char *readdir_packet;
8460 + unsigned long readdir_request_id;
8462 + /* State variables used in libssh2_sftp_write() */
8463 + libssh2_nonblocking_states write_state;
8464 + unsigned char *write_packet;
8465 + unsigned long write_request_id;
8467 + /* State variables used in libssh2_sftp_fstat_ex() */
8468 + libssh2_nonblocking_states fstat_state;
8469 + unsigned char *fstat_packet;
8470 + unsigned long fstat_request_id;
8472 + /* State variables used in libssh2_sftp_unlink_ex() */
8473 + libssh2_nonblocking_states unlink_state;
8474 + unsigned char *unlink_packet;
8475 + unsigned long unlink_request_id;
8477 + /* State variables used in libssh2_sftp_rename_ex() */
8478 + libssh2_nonblocking_states rename_state;
8479 + unsigned char *rename_packet;
8480 + unsigned char *rename_s;
8481 + unsigned long rename_request_id;
8483 + /* State variables used in libssh2_sftp_mkdir() */
8484 + libssh2_nonblocking_states mkdir_state;
8485 + unsigned char *mkdir_packet;
8486 + unsigned long mkdir_request_id;
8488 + /* State variables used in libssh2_sftp_rmdir() */
8489 + libssh2_nonblocking_states rmdir_state;
8490 + unsigned char *rmdir_packet;
8491 + unsigned long rmdir_request_id;
8493 + /* State variables used in libssh2_sftp_stat() */
8494 + libssh2_nonblocking_states stat_state;
8495 + unsigned char *stat_packet;
8496 + unsigned long stat_request_id;
8498 + /* State variables used in libssh2_sftp_symlink() */
8499 + libssh2_nonblocking_states symlink_state;
8500 + unsigned char *symlink_packet;
8501 + unsigned long symlink_request_id;
8504 +#define LIBSSH2_SCP_RESPONSE_BUFLEN 256
8506 +struct _LIBSSH2_SESSION
8508 + /* Memory management callbacks */
8510 + LIBSSH2_ALLOC_FUNC((*alloc));
8511 + LIBSSH2_REALLOC_FUNC((*realloc));
8512 + LIBSSH2_FREE_FUNC((*free));
8514 + /* Other callbacks */
8515 + LIBSSH2_IGNORE_FUNC((*ssh_msg_ignore));
8516 + LIBSSH2_DEBUG_FUNC((*ssh_msg_debug));
8517 + LIBSSH2_DISCONNECT_FUNC((*ssh_msg_disconnect));
8518 + LIBSSH2_MACERROR_FUNC((*macerror));
8519 + LIBSSH2_X11_OPEN_FUNC((*x11));
8521 + /* Method preferences -- NULL yields "load order" */
8523 + char *hostkey_prefs;
8528 + /* Agreed Key Exchange Method */
8529 + const LIBSSH2_KEX_METHOD *kex;
8530 + int burn_optimistic_kexinit:1;
8532 + unsigned char *session_id;
8533 + unsigned long session_id_len;
8535 + /* Server's public key */
8536 + const LIBSSH2_HOSTKEY_METHOD *hostkey;
8537 + void *server_hostkey_abstract;
8539 + /* Either set with libssh2_session_hostkey() (for server mode)
8540 + * Or read from server in (eg) KEXDH_INIT (for client mode)
8542 + unsigned char *server_hostkey;
8543 + unsigned long server_hostkey_len;
8545 + unsigned char server_hostkey_md5[MD5_DIGEST_LENGTH];
8546 +#endif /* ! LIBSSH2_MD5 */
8547 + unsigned char server_hostkey_sha1[SHA_DIGEST_LENGTH];
8549 + /* (remote as source of data -- packet_read ) */
8550 + libssh2_endpoint_data remote;
8552 + /* (local as source of data -- packet_write ) */
8553 + libssh2_endpoint_data local;
8555 + /* Inbound Data buffer -- Sometimes the packet that comes in isn't the packet we're ready for */
8556 + LIBSSH2_PACKET_BRIGADE packets;
8558 + /* Active connection channels */
8559 + LIBSSH2_CHANNEL_BRIGADE channels;
8560 + unsigned long next_channel;
8562 + LIBSSH2_LISTENER *listeners;
8564 + /* Actual I/O socket */
8568 + int socket_block_directions;
8570 + /* Error tracking */
8572 + unsigned long err_msglen;
8573 + int err_should_free;
8576 + /* struct members for packet-level reading */
8577 + struct transportpacket packet;
8578 +#ifdef LIBSSH2DEBUG
8579 + int showmask; /* what debug/trace messages to display */
8582 + /* State variables used in libssh2_banner_send() */
8583 + libssh2_nonblocking_states banner_TxRx_state;
8584 + char banner_TxRx_banner[256];
8585 + ssize_t banner_TxRx_total_send;
8587 + /* State variables used in libssh2_kexinit() */
8588 + libssh2_nonblocking_states kexinit_state;
8589 + unsigned char *kexinit_data;
8590 + size_t kexinit_data_len;
8592 + /* State variables used in libssh2_session_startup() */
8593 + libssh2_nonblocking_states startup_state;
8594 + unsigned char *startup_data;
8595 + unsigned long startup_data_len;
8596 + unsigned char startup_service[sizeof("ssh-userauth") + 5 - 1];
8597 + unsigned long startup_service_length;
8598 + packet_require_state_t startup_req_state;
8599 + key_exchange_state_t startup_key_state;
8601 + /* State variables used in libssh2_session_free() */
8602 + libssh2_nonblocking_states free_state;
8604 + /* State variables used in libssh2_session_disconnect_ex() */
8605 + libssh2_nonblocking_states disconnect_state;
8606 + unsigned char *disconnect_data;
8607 + unsigned long disconnect_data_len;
8609 + /* State variables used in libssh2_packet_read() */
8610 + libssh2_nonblocking_states readPack_state;
8611 + int readPack_encrypted;
8613 + /* State variables used in libssh2_userauth_list() */
8614 + libssh2_nonblocking_states userauth_list_state;
8615 + unsigned char *userauth_list_data;
8616 + unsigned long userauth_list_data_len;
8617 + packet_requirev_state_t userauth_list_packet_requirev_state;
8619 + /* State variables used in libssh2_userauth_password_ex() */
8620 + libssh2_nonblocking_states userauth_pswd_state;
8621 + unsigned char *userauth_pswd_data;
8622 + unsigned char userauth_pswd_data0;
8623 + unsigned long userauth_pswd_data_len;
8624 + char *userauth_pswd_newpw;
8625 + int userauth_pswd_newpw_len;
8626 + packet_requirev_state_t userauth_pswd_packet_requirev_state;
8628 + /* State variables used in libssh2_userauth_hostbased_fromfile_ex() */
8629 + libssh2_nonblocking_states userauth_host_state;
8630 + unsigned char *userauth_host_data;
8631 + unsigned long userauth_host_data_len;
8632 + unsigned char *userauth_host_packet;
8633 + unsigned long userauth_host_packet_len;
8634 + unsigned char *userauth_host_method;
8635 + unsigned long userauth_host_method_len;
8636 + unsigned char *userauth_host_s;
8637 + packet_requirev_state_t userauth_host_packet_requirev_state;
8639 + /* State variables used in libssh2_userauth_publickey_fromfile_ex() */
8640 + libssh2_nonblocking_states userauth_pblc_state;
8641 + unsigned char *userauth_pblc_data;
8642 + unsigned long userauth_pblc_data_len;
8643 + unsigned char *userauth_pblc_packet;
8644 + unsigned long userauth_pblc_packet_len;
8645 + unsigned char *userauth_pblc_method;
8646 + unsigned long userauth_pblc_method_len;
8647 + unsigned char *userauth_pblc_s;
8648 + unsigned char *userauth_pblc_b;
8649 + packet_requirev_state_t userauth_pblc_packet_requirev_state;
8651 + /* State variables used in llibssh2_userauth_keyboard_interactive_ex() */
8652 + libssh2_nonblocking_states userauth_kybd_state;
8653 + unsigned char *userauth_kybd_data;
8654 + unsigned long userauth_kybd_data_len;
8655 + unsigned char *userauth_kybd_packet;
8656 + unsigned long userauth_kybd_packet_len;
8657 + unsigned int userauth_kybd_auth_name_len;
8658 + char *userauth_kybd_auth_name;
8659 + unsigned userauth_kybd_auth_instruction_len;
8660 + char *userauth_kybd_auth_instruction;
8661 + unsigned int userauth_kybd_num_prompts;
8662 + int userauth_kybd_auth_failure;
8663 + LIBSSH2_USERAUTH_KBDINT_PROMPT *userauth_kybd_prompts;
8664 + LIBSSH2_USERAUTH_KBDINT_RESPONSE *userauth_kybd_responses;
8665 + packet_requirev_state_t userauth_kybd_packet_requirev_state;
8667 + /* State variables used in libssh2_channel_open_ex() */
8668 + libssh2_nonblocking_states open_state;
8669 + packet_requirev_state_t open_packet_requirev_state;
8670 + LIBSSH2_CHANNEL *open_channel;
8671 + unsigned char *open_packet;
8672 + unsigned long open_packet_len;
8673 + unsigned char *open_data;
8674 + unsigned long open_data_len;
8675 + unsigned long open_local_channel;
8677 + /* State variables used in libssh2_channel_direct_tcpip_ex() */
8678 + libssh2_nonblocking_states direct_state;
8679 + unsigned char *direct_message;
8680 + unsigned long direct_host_len;
8681 + unsigned long direct_shost_len;
8682 + unsigned long direct_message_len;
8684 + /* State variables used in libssh2_channel_forward_listen_ex() */
8685 + libssh2_nonblocking_states fwdLstn_state;
8686 + unsigned char *fwdLstn_packet;
8687 + unsigned long fwdLstn_host_len;
8688 + unsigned long fwdLstn_packet_len;
8689 + packet_requirev_state_t fwdLstn_packet_requirev_state;
8691 + /* State variables used in libssh2_publickey_init() */
8692 + libssh2_nonblocking_states pkeyInit_state;
8693 + LIBSSH2_PUBLICKEY *pkeyInit_pkey;
8694 + LIBSSH2_CHANNEL *pkeyInit_channel;
8695 + unsigned char *pkeyInit_data;
8696 + unsigned long pkeyInit_data_len;
8698 + /* State variables used in libssh2_packet_add() */
8699 + libssh2_nonblocking_states packAdd_state;
8700 + LIBSSH2_PACKET *packAdd_packet;
8701 + LIBSSH2_CHANNEL *packAdd_channel;
8702 + unsigned long packAdd_data_head;
8703 + key_exchange_state_t packAdd_key_state;
8704 + packet_queue_listener_state_t packAdd_Qlstn_state;
8705 + packet_x11_open_state_t packAdd_x11open_state;
8707 + /* State variables used in fullpacket() */
8708 + libssh2_nonblocking_states fullpacket_state;
8709 + int fullpacket_macstate;
8710 + int fullpacket_payload_len;
8711 + libssh2pack_t fullpacket_packet_type;
8713 + /* State variables used in libssh2_sftp_init() */
8714 + libssh2_nonblocking_states sftpInit_state;
8715 + LIBSSH2_SFTP *sftpInit_sftp;
8716 + LIBSSH2_CHANNEL *sftpInit_channel;
8717 + unsigned char sftpInit_buffer[9]; /* sftp_header(5){excludes request_id} + version_id(4) */
8719 + /* State variables used in libssh2_scp_recv() */
8720 + libssh2_nonblocking_states scpRecv_state;
8721 + unsigned char *scpRecv_command;
8722 + unsigned long scpRecv_command_len;
8723 + unsigned char scpRecv_response[LIBSSH2_SCP_RESPONSE_BUFLEN];
8724 + unsigned long scpRecv_response_len;
8725 + long scpRecv_mode;
8726 +#if defined(HAVE_LONGLONG) && defined(strtoll)
8727 + /* we have the type and we can parse such numbers */
8728 + long long scpRecv_size;
8729 +#define scpsize_strtol strtoll
8731 + long scpRecv_size;
8732 +#define scpsize_strtol strtol
8734 + long scpRecv_mtime;
8735 + long scpRecv_atime;
8736 + char *scpRecv_err_msg;
8737 + long scpRecv_err_len;
8738 + LIBSSH2_CHANNEL *scpRecv_channel;
8740 + /* State variables used in libssh2_scp_send_ex() */
8741 + libssh2_nonblocking_states scpSend_state;
8742 + unsigned char *scpSend_command;
8743 + unsigned long scpSend_command_len;
8744 + unsigned char scpSend_response[LIBSSH2_SCP_RESPONSE_BUFLEN];
8745 + unsigned long scpSend_response_len;
8746 + char *scpSend_err_msg;
8747 + long scpSend_err_len;
8748 + LIBSSH2_CHANNEL *scpSend_channel;
8751 +/* session.state bits */
8752 +#define LIBSSH2_STATE_EXCHANGING_KEYS 0x00000001
8753 +#define LIBSSH2_STATE_NEWKEYS 0x00000002
8754 +#define LIBSSH2_STATE_AUTHENTICATED 0x00000004
8755 +#define LIBSSH2_STATE_KEX_ACTIVE 0x00000008
8757 +/* session.flag helpers */
8758 +#ifdef MSG_NOSIGNAL
8759 +#define LIBSSH2_SOCKET_SEND_FLAGS(session) (((session)->flags & LIBSSH2_FLAG_SIGPIPE) ? 0 : MSG_NOSIGNAL)
8760 +#define LIBSSH2_SOCKET_RECV_FLAGS(session) (((session)->flags & LIBSSH2_FLAG_SIGPIPE) ? 0 : MSG_NOSIGNAL)
8762 +/* If MSG_NOSIGNAL isn't defined we're SOL on blocking SIGPIPE */
8763 +#define LIBSSH2_SOCKET_SEND_FLAGS(session) 0
8764 +#define LIBSSH2_SOCKET_RECV_FLAGS(session) 0
8767 +/* libssh2 extensible ssh api, ultimately I'd like to allow loading additional methods via .so/.dll */
8769 +struct _LIBSSH2_KEX_METHOD
8773 + /* Key exchange, populates session->* and returns 0 on success, non-0 on error */
8774 + int (*exchange_keys) (LIBSSH2_SESSION * session,
8775 + key_exchange_state_low_t * key_state);
8780 +struct _LIBSSH2_HOSTKEY_METHOD
8783 + unsigned long hash_len;
8785 + int (*init) (LIBSSH2_SESSION * session, const unsigned char *hostkey_data,
8786 + unsigned long hostkey_data_len, void **abstract);
8787 + int (*initPEM) (LIBSSH2_SESSION * session, const char *privkeyfile,
8788 + unsigned const char *passphrase, void **abstract);
8789 + int (*sig_verify) (LIBSSH2_SESSION * session, const unsigned char *sig,
8790 + unsigned long sig_len, const unsigned char *m,
8791 + unsigned long m_len, void **abstract);
8792 + int (*signv) (LIBSSH2_SESSION * session, unsigned char **signature,
8793 + unsigned long *signature_len, unsigned long veccount,
8794 + const struct iovec datavec[], void **abstract);
8795 + int (*encrypt) (LIBSSH2_SESSION * session, unsigned char **dst,
8796 + unsigned long *dst_len, const unsigned char *src,
8797 + unsigned long src_len, void **abstract);
8798 + int (*dtor) (LIBSSH2_SESSION * session, void **abstract);
8801 +struct _LIBSSH2_CRYPT_METHOD
8807 + /* iv and key sizes (-1 for variable length) */
8813 + int (*init) (LIBSSH2_SESSION * session,
8814 + const LIBSSH2_CRYPT_METHOD * method, unsigned char *iv,
8815 + int *free_iv, unsigned char *secret, int *free_secret,
8816 + int encrypt, void **abstract);
8817 + int (*crypt) (LIBSSH2_SESSION * session, unsigned char *block,
8819 + int (*dtor) (LIBSSH2_SESSION * session, void **abstract);
8821 + _libssh2_cipher_type(algo);
8824 +struct _LIBSSH2_COMP_METHOD
8828 + int (*init) (LIBSSH2_SESSION * session, int compress, void **abstract);
8829 + int (*comp) (LIBSSH2_SESSION * session, int compress, unsigned char **dest,
8830 + unsigned long *dest_len, unsigned long payload_limit,
8831 + int *free_dest, const unsigned char *src,
8832 + unsigned long src_len, void **abstract);
8833 + int (*dtor) (LIBSSH2_SESSION * session, int compress, void **abstract);
8836 +struct _LIBSSH2_MAC_METHOD
8840 + /* The length of a given MAC packet */
8843 + /* integrity key length */
8846 + /* Message Authentication Code Hashing algo */
8847 + int (*init) (LIBSSH2_SESSION * session, unsigned char *key, int *free_key,
8849 + int (*hash) (LIBSSH2_SESSION * session, unsigned char *buf,
8850 + unsigned long seqno, const unsigned char *packet,
8851 + unsigned long packet_len, const unsigned char *addtl,
8852 + unsigned long addtl_len, void **abstract);
8853 + int (*dtor) (LIBSSH2_SESSION * session, void **abstract);
8856 +#define LIBSSH2_DBG_TRANS 1
8857 +#define LIBSSH2_DBG_KEX 2
8858 +#define LIBSSH2_DBG_AUTH 3
8859 +#define LIBSSH2_DBG_CONN 4
8860 +#define LIBSSH2_DBG_SCP 5
8861 +#define LIBSSH2_DBG_SFTP 6
8862 +#define LIBSSH2_DBG_ERROR 7
8863 +#define LIBSSH2_DBG_PUBLICKEY 8
8864 +#ifdef LIBSSH2DEBUG
8865 +void _libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format,
8868 +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
8870 +#define _libssh2_debug(x,y,z, __VA_ARGS__) do {} while (0)
8871 +#elif defined(__GNUC__)
8873 +#define _libssh2_debug(x,y,z,...) do {} while (0)
8875 +/* no gcc and not C99, do static and hopefully inline */
8877 +_libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, ...)
8883 +#ifdef LIBSSH2DEBUG
8884 +#define libssh2_error(session, errcode, errmsg, should_free) \
8886 + if (session->err_msg && session->err_should_free) { \
8887 + LIBSSH2_FREE(session, session->err_msg); \
8889 + session->err_msg = (char *)errmsg; \
8890 + session->err_msglen = strlen(errmsg); \
8891 + session->err_should_free = should_free; \
8892 + session->err_code = errcode; \
8893 + _libssh2_debug(session, LIBSSH2_DBG_ERROR, "%d - %s", session->err_code, session->err_msg); \
8896 +#else /* ! LIBSSH2DEBUG */
8898 +#define libssh2_error(session, errcode, errmsg, should_free) \
8900 + if (session->err_msg && session->err_should_free) { \
8901 + LIBSSH2_FREE(session, session->err_msg); \
8903 + session->err_msg = (char *)errmsg; \
8904 + session->err_msglen = strlen(errmsg); \
8905 + session->err_should_free = should_free; \
8906 + session->err_code = errcode; \
8909 +#endif /* ! LIBSSH2DEBUG */
8912 +#define LIBSSH2_SOCKET_UNKNOWN 1
8913 +#define LIBSSH2_SOCKET_CONNECTED 0
8914 +#define LIBSSH2_SOCKET_DISCONNECTED -1
8916 +/* Initial packet state, prior to MAC check */
8917 +#define LIBSSH2_MAC_UNCONFIRMED 1
8918 +/* When MAC type is "none" (proto initiation phase) all packets are deemed "confirmed" */
8919 +#define LIBSSH2_MAC_CONFIRMED 0
8920 +/* Something very bad is going on */
8921 +#define LIBSSH2_MAC_INVALID -1
8923 +/* SSH Packet Types -- Defined by internet draft */
8924 +/* Transport Layer */
8925 +#define SSH_MSG_DISCONNECT 1
8926 +#define SSH_MSG_IGNORE 2
8927 +#define SSH_MSG_UNIMPLEMENTED 3
8928 +#define SSH_MSG_DEBUG 4
8929 +#define SSH_MSG_SERVICE_REQUEST 5
8930 +#define SSH_MSG_SERVICE_ACCEPT 6
8932 +#define SSH_MSG_KEXINIT 20
8933 +#define SSH_MSG_NEWKEYS 21
8935 +/* diffie-hellman-group1-sha1 */
8936 +#define SSH_MSG_KEXDH_INIT 30
8937 +#define SSH_MSG_KEXDH_REPLY 31
8939 +/* diffie-hellman-group-exchange-sha1 */
8940 +#define SSH_MSG_KEX_DH_GEX_REQUEST_OLD 30
8941 +#define SSH_MSG_KEX_DH_GEX_REQUEST 34
8942 +#define SSH_MSG_KEX_DH_GEX_GROUP 31
8943 +#define SSH_MSG_KEX_DH_GEX_INIT 32
8944 +#define SSH_MSG_KEX_DH_GEX_REPLY 33
8946 +/* User Authentication */
8947 +#define SSH_MSG_USERAUTH_REQUEST 50
8948 +#define SSH_MSG_USERAUTH_FAILURE 51
8949 +#define SSH_MSG_USERAUTH_SUCCESS 52
8950 +#define SSH_MSG_USERAUTH_BANNER 53
8952 +/* "public key" method */
8953 +#define SSH_MSG_USERAUTH_PK_OK 60
8954 +/* "password" method */
8955 +#define SSH_MSG_USERAUTH_PASSWD_CHANGEREQ 60
8956 +/* "keyboard-interactive" method */
8957 +#define SSH_MSG_USERAUTH_INFO_REQUEST 60
8958 +#define SSH_MSG_USERAUTH_INFO_RESPONSE 61
8961 +#define SSH_MSG_GLOBAL_REQUEST 80
8962 +#define SSH_MSG_REQUEST_SUCCESS 81
8963 +#define SSH_MSG_REQUEST_FAILURE 82
8965 +#define SSH_MSG_CHANNEL_OPEN 90
8966 +#define SSH_MSG_CHANNEL_OPEN_CONFIRMATION 91
8967 +#define SSH_MSG_CHANNEL_OPEN_FAILURE 92
8968 +#define SSH_MSG_CHANNEL_WINDOW_ADJUST 93
8969 +#define SSH_MSG_CHANNEL_DATA 94
8970 +#define SSH_MSG_CHANNEL_EXTENDED_DATA 95
8971 +#define SSH_MSG_CHANNEL_EOF 96
8972 +#define SSH_MSG_CHANNEL_CLOSE 97
8973 +#define SSH_MSG_CHANNEL_REQUEST 98
8974 +#define SSH_MSG_CHANNEL_SUCCESS 99
8975 +#define SSH_MSG_CHANNEL_FAILURE 100
8977 +void libssh2_session_shutdown(LIBSSH2_SESSION * session);
8979 +unsigned long libssh2_ntohu32(const unsigned char *buf);
8980 +libssh2_uint64_t libssh2_ntohu64(const unsigned char *buf);
8981 +void libssh2_htonu32(unsigned char *buf, unsigned long val);
8982 +void libssh2_htonu64(unsigned char *buf, libssh2_uint64_t val);
8984 +#define LIBSSH2_READ_TIMEOUT 60 /* generic timeout in seconds used when
8985 + waiting for more data to arrive */
8986 +int libssh2_waitsocket(LIBSSH2_SESSION * session, long seconds);
8989 +/* CAUTION: some of these error codes are returned in the public API and is
8990 + there known with other #defined names from the public header file. They
8991 + should not be changed. */
8993 +#define PACKET_TIMEOUT -7
8994 +#define PACKET_BADUSE -6
8995 +#define PACKET_COMPRESS -5
8996 +#define PACKET_TOOBIG -4
8997 +#define PACKET_ENOMEM -3
8998 +#define PACKET_EAGAIN LIBSSH2_ERROR_EAGAIN
8999 +#define PACKET_FAIL -1
9000 +#define PACKET_NONE 0
9002 +libssh2pack_t libssh2_packet_read(LIBSSH2_SESSION * session);
9004 +int libssh2_packet_ask_ex(LIBSSH2_SESSION * session, unsigned char packet_type,
9005 + unsigned char **data, unsigned long *data_len,
9006 + unsigned long match_ofs,
9007 + const unsigned char *match_buf,
9008 + unsigned long match_len, int poll_socket);
9010 +int libssh2_packet_askv_ex(LIBSSH2_SESSION * session,
9011 + const unsigned char *packet_types,
9012 + unsigned char **data, unsigned long *data_len,
9013 + unsigned long match_ofs,
9014 + const unsigned char *match_buf,
9015 + unsigned long match_len, int poll_socket);
9016 +int libssh2_packet_require_ex(LIBSSH2_SESSION * session,
9017 + unsigned char packet_type, unsigned char **data,
9018 + unsigned long *data_len, unsigned long match_ofs,
9019 + const unsigned char *match_buf,
9020 + unsigned long match_len,
9021 + packet_require_state_t * state);
9022 +int libssh2_packet_requirev_ex(LIBSSH2_SESSION * session,
9023 + const unsigned char *packet_types,
9024 + unsigned char **data, unsigned long *data_len,
9025 + unsigned long match_ofs,
9026 + const unsigned char *match_buf,
9027 + unsigned long match_len,
9028 + packet_requirev_state_t * state);
9029 +int libssh2_packet_burn(LIBSSH2_SESSION * session,
9030 + libssh2_nonblocking_states * state);
9031 +int libssh2_packet_write(LIBSSH2_SESSION * session, unsigned char *data,
9032 + unsigned long data_len);
9033 +int libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
9034 + size_t datalen, int macstate);
9035 +int libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange,
9036 + key_exchange_state_t * state);
9037 +unsigned long libssh2_channel_nextid(LIBSSH2_SESSION * session);
9038 +LIBSSH2_CHANNEL *libssh2_channel_locate(LIBSSH2_SESSION * session,
9039 + unsigned long channel_id);
9040 +unsigned long libssh2_channel_packet_data_len(LIBSSH2_CHANNEL * channel,
9043 +/* this is the lib-internal set blocking function */
9044 +int _libssh2_session_set_blocking(LIBSSH2_SESSION * session, int blocking);
9046 +/* Let crypt.c/hostkey.c/comp.c/mac.c expose their method structs */
9047 +const LIBSSH2_CRYPT_METHOD **libssh2_crypt_methods(void);
9048 +const LIBSSH2_HOSTKEY_METHOD **libssh2_hostkey_methods(void);
9049 +const LIBSSH2_COMP_METHOD **libssh2_comp_methods(void);
9050 +const LIBSSH2_MAC_METHOD **libssh2_mac_methods(void);
9052 +/* Language API doesn't exist yet. Just act like we've agreed on a language */
9053 +#define libssh2_kex_agree_lang(session, endpoint, str, str_len) 0
9056 +int _libssh2_pem_parse(LIBSSH2_SESSION * session,
9057 + const char *headerbegin,
9058 + const char *headerend,
9059 + FILE * fp, unsigned char **data, unsigned int *datalen);
9060 +int _libssh2_pem_decode_sequence(unsigned char **data, unsigned int *datalen);
9061 +int _libssh2_pem_decode_integer(unsigned char **data, unsigned int *datalen,
9062 + unsigned char **i, unsigned int *ilen);
9064 +#endif /* LIBSSH2_H */
9066 Property changes on: libssh2/src/libssh2_priv.h
9067 ___________________________________________________________________
9068 Added: svn:mime-type
9071 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
9072 Added: cvs2svn:cvs-rev
9074 Added: svn:eol-style
9076 Added: svn:executable
9079 Index: libssh2/src/sftp.c
9080 ===================================================================
9081 --- libssh2/src/sftp.c (.../tags/RELEASE_0_11_0)
9082 +++ libssh2/src/sftp.c (.../trunk)
9084 +/* Copyright (c) 2004-2008, Sara Golemon <sarag@libssh2.org>
9085 + * All rights reserved.
9087 + * Redistribution and use in source and binary forms,
9088 + * with or without modification, are permitted provided
9089 + * that the following conditions are met:
9091 + * Redistributions of source code must retain the above
9092 + * copyright notice, this list of conditions and the
9093 + * following disclaimer.
9095 + * Redistributions in binary form must reproduce the above
9096 + * copyright notice, this list of conditions and the following
9097 + * disclaimer in the documentation and/or other materials
9098 + * provided with the distribution.
9100 + * Neither the name of the copyright holder nor the names
9101 + * of any other contributors may be used to endorse or
9102 + * promote products derived from this software without
9103 + * specific prior written permission.
9105 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
9106 + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
9107 + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
9108 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
9109 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
9110 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
9111 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
9112 + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
9113 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
9114 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
9115 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
9116 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
9117 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
9121 +#include "libssh2_priv.h"
9122 +#include "libssh2_sftp.h"
9124 +/* Note: Version 6 was documented at the time of writing
9125 + * However it was marked as "DO NOT IMPLEMENT" due to pending changes
9127 + * This release of libssh2 implements Version 5 with automatic downgrade
9128 + * based on server's declaration
9131 +/* SFTP packet types */
9132 +#define SSH_FXP_INIT 1
9133 +#define SSH_FXP_VERSION 2
9134 +#define SSH_FXP_OPEN 3
9135 +#define SSH_FXP_CLOSE 4
9136 +#define SSH_FXP_READ 5
9137 +#define SSH_FXP_WRITE 6
9138 +#define SSH_FXP_LSTAT 7
9139 +#define SSH_FXP_FSTAT 8
9140 +#define SSH_FXP_SETSTAT 9
9141 +#define SSH_FXP_FSETSTAT 10
9142 +#define SSH_FXP_OPENDIR 11
9143 +#define SSH_FXP_READDIR 12
9144 +#define SSH_FXP_REMOVE 13
9145 +#define SSH_FXP_MKDIR 14
9146 +#define SSH_FXP_RMDIR 15
9147 +#define SSH_FXP_REALPATH 16
9148 +#define SSH_FXP_STAT 17
9149 +#define SSH_FXP_RENAME 18
9150 +#define SSH_FXP_READLINK 19
9151 +#define SSH_FXP_SYMLINK 20
9152 +#define SSH_FXP_STATUS 101
9153 +#define SSH_FXP_HANDLE 102
9154 +#define SSH_FXP_DATA 103
9155 +#define SSH_FXP_NAME 104
9156 +#define SSH_FXP_ATTRS 105
9157 +#define SSH_FXP_EXTENDED 200
9158 +#define SSH_FXP_EXTENDED_REPLY 201
9160 +#define LIBSSH2_SFTP_HANDLE_FILE 0
9161 +#define LIBSSH2_SFTP_HANDLE_DIR 1
9164 +#define LIBSSH2_SFTP_ATTR_PFILETYPE_FILE 0100000
9166 +#define LIBSSH2_SFTP_ATTR_PFILETYPE_DIR 0040000
9168 +/* {{{ sftp_packet_add
9169 + * Add a packet to the SFTP packet brigade
9172 +sftp_packet_add(LIBSSH2_SFTP * sftp, unsigned char *data,
9173 + unsigned long data_len)
9175 + LIBSSH2_SESSION *session = sftp->channel->session;
9176 + LIBSSH2_PACKET *packet;
9178 + _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Received packet %d (len %d)",
9179 + (int) data[0], data_len);
9180 + packet = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PACKET));
9182 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
9183 + "Unable to allocate datablock for SFTP packet", 0);
9186 + memset(packet, 0, sizeof(LIBSSH2_PACKET));
9188 + packet->data = data;
9189 + packet->data_len = data_len;
9190 + packet->data_head = 5;
9191 + packet->brigade = &sftp->packets;
9192 + packet->next = NULL;
9193 + packet->prev = sftp->packets.tail;
9194 + if (packet->prev) {
9195 + packet->prev->next = packet;
9197 + sftp->packets.head = packet;
9199 + sftp->packets.tail = packet;
9206 +/* {{{ sftp_packet_read
9207 + * Frame an SFTP packet off the channel
9210 +sftp_packet_read(LIBSSH2_SFTP * sftp)
9212 + LIBSSH2_CHANNEL *channel = sftp->channel;
9213 + LIBSSH2_SESSION *session = channel->session;
9214 + unsigned char buffer[4]; /* To store the packet length */
9215 + unsigned char *packet;
9216 + unsigned long packet_len, packet_received;
9217 + ssize_t bytes_received;
9220 + _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Waiting for packet");
9223 + /* If there was a previous partial, start using it */
9224 + if (sftp->partial_packet) {
9226 + packet = sftp->partial_packet;
9227 + packet_len = sftp->partial_len;
9228 + packet_received = sftp->partial_received;
9229 + sftp->partial_packet = NULL;
9231 + _libssh2_debug(session, LIBSSH2_DBG_SFTP,
9232 + "partial read cont, len: %lu", packet_len);
9235 + rc = libssh2_channel_read_ex(channel, 0, (char *) buffer, 4);
9236 + if (rc == PACKET_EAGAIN) {
9237 + return PACKET_EAGAIN;
9239 + else if (4 != rc) {
9240 + /* TODO: this is stupid since we can in fact get 1-3 bytes in a
9241 + legitimate working case as well if the connection happens to be
9242 + super slow or something */
9243 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
9244 + "Timeout waiting for FXP packet", 0);
9248 + packet_len = libssh2_ntohu32(buffer);
9249 + _libssh2_debug(session, LIBSSH2_DBG_SFTP,
9250 + "Data begin - Packet Length: %lu", packet_len);
9251 + if (packet_len > LIBSSH2_SFTP_PACKET_MAXLEN) {
9252 + libssh2_error(session, LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED,
9253 + "SFTP packet too large", 0);
9257 + packet = LIBSSH2_ALLOC(session, packet_len);
9259 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
9260 + "Unable to allocate SFTP packet", 0);
9264 + packet_received = 0;
9267 + /* Read as much of the packet as we can */
9268 + while (packet_len > packet_received) {
9270 + libssh2_channel_read_ex(channel, 0,
9271 + (char *) packet + packet_received,
9272 + packet_len - packet_received);
9274 + if (bytes_received == PACKET_EAGAIN) {
9276 + * We received EAGAIN, save what we have and
9277 + * return to EAGAIN to the caller
9279 + sftp->partial_packet = packet;
9280 + sftp->partial_len = packet_len;
9281 + sftp->partial_received = packet_received;
9284 + return PACKET_EAGAIN;
9286 + else if (bytes_received < 0) {
9287 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
9288 + "Receive error waiting for SFTP packet", 0);
9289 + LIBSSH2_FREE(session, packet);
9292 + packet_received += bytes_received;
9295 + if (sftp_packet_add(sftp, packet, packet_len)) {
9296 + LIBSSH2_FREE(session, packet);
9305 +/* {{{ sftp_packet_ask
9306 + * A la libssh2_packet_ask()
9309 +sftp_packet_ask(LIBSSH2_SFTP * sftp, unsigned char packet_type,
9310 + unsigned long request_id, unsigned char **data,
9311 + unsigned long *data_len, int poll_channel)
9313 + LIBSSH2_SESSION *session = sftp->channel->session;
9314 + LIBSSH2_PACKET *packet = sftp->packets.head;
9315 + unsigned char match_buf[5];
9316 + int match_len = 5;
9318 + _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Asking for %d packet",
9319 + (int) packet_type);
9320 + if (poll_channel) {
9321 + int ret = sftp_packet_read(sftp);
9322 + if (ret == PACKET_EAGAIN) {
9323 + return PACKET_EAGAIN;
9324 + } else if (ret < 0) {
9329 + match_buf[0] = packet_type;
9330 + if (packet_type == SSH_FXP_VERSION) {
9331 + /* Special consideration when matching VERSION packet */
9334 + libssh2_htonu32(match_buf + 1, request_id);
9338 + if (strncmp((char *) packet->data, (char *) match_buf, match_len) == 0) {
9339 + *data = packet->data;
9340 + *data_len = packet->data_len;
9342 + if (packet->prev) {
9343 + packet->prev->next = packet->next;
9345 + sftp->packets.head = packet->next;
9348 + if (packet->next) {
9349 + packet->next->prev = packet->prev;
9351 + sftp->packets.tail = packet->prev;
9354 + LIBSSH2_FREE(session, packet);
9358 + packet = packet->next;
9365 +/* {{{ sftp_packet_require
9366 + * A la libssh2_packet_require
9369 +sftp_packet_require(LIBSSH2_SFTP * sftp, unsigned char packet_type,
9370 + unsigned long request_id, unsigned char **data,
9371 + unsigned long *data_len)
9373 + LIBSSH2_SESSION *session = sftp->channel->session;
9376 + _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Requiring %d packet",
9377 + (int) packet_type);
9379 + if (sftp_packet_ask(sftp, packet_type, request_id, data,
9380 + data_len, 0) == 0) {
9381 + /* The right packet was available in the packet brigade */
9385 + while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
9386 + ret = sftp_packet_read(sftp);
9387 + if (ret == PACKET_EAGAIN) {
9388 + return PACKET_EAGAIN;
9389 + } else if (ret <= 0) {
9393 + if (packet_type == ret) {
9394 + /* Be lazy, let packet_ask pull it out of the brigade */
9395 + return sftp_packet_ask(sftp, packet_type, request_id, data,
9400 + /* Only reached if the socket died */
9406 +/* {{{ sftp_packet_requirev
9407 + * Require one of N possible reponses
9410 +sftp_packet_requirev(LIBSSH2_SFTP * sftp, int num_valid_responses,
9411 + const unsigned char *valid_responses,
9412 + unsigned long request_id, unsigned char **data,
9413 + unsigned long *data_len)
9418 + /* If no timeout is active, start a new one */
9419 + if (sftp->requirev_start == 0) {
9420 + sftp->requirev_start = time(NULL);
9423 + while (sftp->channel->session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
9424 + for(i = 0; i < num_valid_responses; i++) {
9425 + if (sftp_packet_ask(sftp, valid_responses[i], request_id,
9426 + data, data_len, 0) == 0) {
9428 + * Set to zero before all returns to say
9429 + * the timeout is not active
9431 + sftp->requirev_start = 0;
9436 + ret = sftp_packet_read(sftp);
9437 + if ((ret < 0) && (ret != PACKET_EAGAIN)) {
9438 + sftp->requirev_start = 0;
9440 + } else if (ret <= 0) {
9441 + /* prevent busy-looping */
9443 + LIBSSH2_READ_TIMEOUT - (time(NULL) - sftp->requirev_start);
9446 + sftp->requirev_start = 0;
9447 + return PACKET_TIMEOUT;
9448 + } else if (sftp->channel->session->socket_block
9449 + && (libssh2_waitsocket(sftp->channel->session, left) <=
9451 + sftp->requirev_start = 0;
9452 + return PACKET_TIMEOUT;
9453 + } else if (ret == PACKET_EAGAIN) {
9454 + return PACKET_EAGAIN;
9459 + sftp->requirev_start = 0;
9465 +/* {{{ libssh2_sftp_attrsize
9466 + * Size that attr will occupy when turned into a bin struct
9469 +libssh2_sftp_attrsize(const LIBSSH2_SFTP_ATTRIBUTES * attrs)
9471 + int attrsize = 4; /* flags(4) */
9477 + if (attrs->flags & LIBSSH2_SFTP_ATTR_SIZE)
9479 + if (attrs->flags & LIBSSH2_SFTP_ATTR_UIDGID)
9481 + if (attrs->flags & LIBSSH2_SFTP_ATTR_PERMISSIONS)
9483 + if (attrs->flags & LIBSSH2_SFTP_ATTR_ACMODTIME)
9484 + attrsize += 8; /* atime + mtime as u32 */
9491 +/* {{{ libssh2_sftp_attr2bin
9492 + * Populate attributes into an SFTP block
9495 +libssh2_sftp_attr2bin(unsigned char *p, const LIBSSH2_SFTP_ATTRIBUTES * attrs)
9497 + unsigned char *s = p;
9498 + unsigned long flag_mask =
9499 + LIBSSH2_SFTP_ATTR_SIZE | LIBSSH2_SFTP_ATTR_UIDGID |
9500 + LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME;
9502 + /* TODO: When we add SFTP4+ functionality flag_mask can get additional bits */
9505 + libssh2_htonu32(s, 0);
9509 + libssh2_htonu32(s, attrs->flags & flag_mask);
9512 + if (attrs->flags & LIBSSH2_SFTP_ATTR_SIZE) {
9513 + libssh2_htonu64(s, attrs->filesize);
9517 + if (attrs->flags & LIBSSH2_SFTP_ATTR_UIDGID) {
9518 + libssh2_htonu32(s, attrs->uid);
9520 + libssh2_htonu32(s, attrs->gid);
9524 + if (attrs->flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) {
9525 + libssh2_htonu32(s, attrs->permissions);
9529 + if (attrs->flags & LIBSSH2_SFTP_ATTR_ACMODTIME) {
9530 + libssh2_htonu32(s, attrs->atime);
9532 + libssh2_htonu32(s, attrs->mtime);
9541 +/* {{{ libssh2_sftp_bin2attr
9544 +libssh2_sftp_bin2attr(LIBSSH2_SFTP_ATTRIBUTES * attrs, const unsigned char *p)
9546 + const unsigned char *s = p;
9548 + memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
9549 + attrs->flags = libssh2_ntohu32(s);
9552 + if (attrs->flags & LIBSSH2_SFTP_ATTR_SIZE) {
9553 + attrs->filesize = libssh2_ntohu64(s);
9557 + if (attrs->flags & LIBSSH2_SFTP_ATTR_UIDGID) {
9558 + attrs->uid = libssh2_ntohu32(s);
9560 + attrs->gid = libssh2_ntohu32(s);
9564 + if (attrs->flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) {
9565 + attrs->permissions = libssh2_ntohu32(s);
9569 + if (attrs->flags & LIBSSH2_SFTP_ATTR_ACMODTIME) {
9570 + attrs->atime = libssh2_ntohu32(s);
9572 + attrs->mtime = libssh2_ntohu32(s);
9585 +LIBSSH2_CHANNEL_CLOSE_FUNC(libssh2_sftp_dtor);
9587 +/* {{{ libssh2_sftp_dtor
9588 + * Shutdown an SFTP stream when the channel closes
9590 +LIBSSH2_CHANNEL_CLOSE_FUNC(libssh2_sftp_dtor)
9592 + LIBSSH2_SFTP *sftp = (LIBSSH2_SFTP *) (*channel_abstract);
9594 + (void) session_abstract;
9597 + /* Loop through handles closing them */
9598 + while (sftp->handles) {
9599 + libssh2_sftp_close_handle(sftp->handles);
9602 + /* Free the partial packet storage for sftp_packet_read */
9603 + if (sftp->partial_packet) {
9604 + LIBSSH2_FREE(session, sftp->partial_packet);
9607 + /* Free the packet storage for _libssh2_sftp_packet_readdir */
9608 + if (sftp->readdir_packet) {
9609 + LIBSSH2_FREE(session, sftp->readdir_packet);
9612 + LIBSSH2_FREE(session, sftp);
9617 +/* {{{ libssh2_sftp_init
9618 + * Startup an SFTP session
9620 + * NOTE: Will block in a busy loop on error. This has to be done,
9621 + * otherwise the blocking error code would erase the true
9622 + * cause of the error.
9624 +LIBSSH2_API LIBSSH2_SFTP *
9625 +libssh2_sftp_init(LIBSSH2_SESSION * session)
9627 + unsigned char *data, *s;
9628 + unsigned long data_len;
9631 + if (session->sftpInit_state == libssh2_NB_state_idle) {
9632 + _libssh2_debug(session, LIBSSH2_DBG_SFTP,
9633 + "Initializing SFTP subsystem");
9635 + session->sftpInit_sftp = NULL;
9637 + session->sftpInit_state = libssh2_NB_state_created;
9640 + if (session->sftpInit_state == libssh2_NB_state_created) {
9641 + session->sftpInit_channel =
9642 + libssh2_channel_open_ex(session, "session", sizeof("session") - 1,
9643 + LIBSSH2_CHANNEL_WINDOW_DEFAULT,
9644 + LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0);
9645 + if (!session->sftpInit_channel) {
9646 + if (libssh2_session_last_errno(session) == LIBSSH2_ERROR_EAGAIN) {
9647 + libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
9648 + "Would block starting up channel", 0);
9650 + } else if (libssh2_session_last_errno(session) !=
9651 + LIBSSH2_ERROR_EAGAIN) {
9652 + libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE,
9653 + "Unable to startup channel", 0);
9654 + session->sftpInit_state = libssh2_NB_state_idle;
9659 + session->sftpInit_state = libssh2_NB_state_sent;
9662 + if (session->sftpInit_state == libssh2_NB_state_sent) {
9663 + rc = libssh2_channel_process_startup(session->sftpInit_channel,
9665 + sizeof("subsystem") - 1, "sftp",
9667 + if (rc == PACKET_EAGAIN) {
9668 + libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
9669 + "Would block to request SFTP subsystem", 0);
9672 + libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE,
9673 + "Unable to request SFTP subsystem", 0);
9674 + goto sftp_init_error;
9677 + session->sftpInit_state = libssh2_NB_state_sent1;
9680 + if (session->sftpInit_state == libssh2_NB_state_sent1) {
9681 + rc = libssh2_channel_handle_extended_data2(session->sftpInit_channel,
9682 + LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE);
9683 + if (rc == PACKET_EAGAIN) {
9684 + libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
9685 + "Would block requesting handle extended data", 0);
9689 + session->sftpInit_sftp = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_SFTP));
9690 + if (!session->sftpInit_sftp) {
9691 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
9692 + "Unable to allocate a new SFTP structure", 0);
9693 + goto sftp_init_error;
9695 + memset(session->sftpInit_sftp, 0, sizeof(LIBSSH2_SFTP));
9696 + session->sftpInit_sftp->channel = session->sftpInit_channel;
9697 + session->sftpInit_sftp->request_id = 0;
9699 + libssh2_htonu32(session->sftpInit_buffer, 5);
9700 + session->sftpInit_buffer[4] = SSH_FXP_INIT;
9701 + libssh2_htonu32(session->sftpInit_buffer + 5, LIBSSH2_SFTP_VERSION);
9703 + _libssh2_debug(session, LIBSSH2_DBG_SFTP,
9704 + "Sending FXP_INIT packet advertising version %d support",
9705 + (int) LIBSSH2_SFTP_VERSION);
9707 + session->sftpInit_state = libssh2_NB_state_sent2;
9710 + if (session->sftpInit_state == libssh2_NB_state_sent2) {
9711 + rc = libssh2_channel_write_ex(session->sftpInit_channel, 0,
9712 + (char *) session->sftpInit_buffer, 9);
9713 + if (rc == PACKET_EAGAIN) {
9714 + libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
9715 + "Would block sending SSH_FXP_INIT", 0);
9717 + } else if (9 != rc) {
9718 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
9719 + "Unable to send SSH_FXP_INIT", 0);
9720 + goto sftp_init_error;
9723 + session->sftpInit_state = libssh2_NB_state_sent3;
9726 + /* For initiallization we are requiring blocking, probably reasonable */
9727 + rc = sftp_packet_require(session->sftpInit_sftp, SSH_FXP_VERSION,
9728 + 0, &data, &data_len);
9729 + if (rc == PACKET_EAGAIN) {
9730 + libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
9731 + "Would block waiting for response from SFTP subsystem",
9735 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
9736 + "Timeout waiting for response from SFTP subsystem", 0);
9737 + goto sftp_init_error;
9739 + if (data_len < 5) {
9740 + libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
9741 + "Invalid SSH_FXP_VERSION response", 0);
9742 + goto sftp_init_error;
9746 + session->sftpInit_sftp->version = libssh2_ntohu32(s);
9748 + if (session->sftpInit_sftp->version > LIBSSH2_SFTP_VERSION) {
9749 + _libssh2_debug(session, LIBSSH2_DBG_SFTP,
9750 + "Truncating remote SFTP version from %lu",
9751 + session->sftpInit_sftp->version);
9752 + session->sftpInit_sftp->version = LIBSSH2_SFTP_VERSION;
9754 + _libssh2_debug(session, LIBSSH2_DBG_SFTP,
9755 + "Enabling SFTP version %lu compatability",
9756 + session->sftpInit_sftp->version);
9757 + while (s < (data + data_len)) {
9758 + unsigned char *extension_name, *extension_data;
9759 + unsigned long extname_len, extdata_len;
9761 + extname_len = libssh2_ntohu32(s);
9763 + extension_name = s;
9766 + extdata_len = libssh2_ntohu32(s);
9768 + extension_data = s;
9771 + /* TODO: Actually process extensions */
9773 + LIBSSH2_FREE(session, data);
9775 + /* Make sure that when the channel gets closed, the SFTP service is shut down too */
9776 + session->sftpInit_sftp->channel->abstract = session->sftpInit_sftp;
9777 + session->sftpInit_sftp->channel->close_cb = libssh2_sftp_dtor;
9779 + session->sftpInit_state = libssh2_NB_state_idle;
9780 + return session->sftpInit_sftp;
9783 + while (libssh2_channel_free(session->sftpInit_channel) == PACKET_EAGAIN);
9784 + session->sftpInit_channel = NULL;
9785 + if (session->sftpInit_sftp) {
9786 + LIBSSH2_FREE(session, session->sftpInit_sftp);
9787 + session->sftpInit_sftp = NULL;
9789 + session->sftpInit_state = libssh2_NB_state_idle;
9795 +/* {{{ libssh2_sftp_shutdown
9796 + * Shutsdown the SFTP subsystem
9799 +libssh2_sftp_shutdown(LIBSSH2_SFTP * sftp)
9802 + * Make sure all memory used in the state variables are free
9804 + if (sftp->partial_packet) {
9805 + LIBSSH2_FREE(sftp->channel->session, sftp->partial_packet);
9806 + sftp->partial_packet = NULL;
9808 + if (sftp->open_packet) {
9809 + LIBSSH2_FREE(sftp->channel->session, sftp->open_packet);
9810 + sftp->open_packet = NULL;
9812 + if (sftp->readdir_packet) {
9813 + LIBSSH2_FREE(sftp->channel->session, sftp->readdir_packet);
9814 + sftp->readdir_packet = NULL;
9816 + if (sftp->write_packet) {
9817 + LIBSSH2_FREE(sftp->channel->session, sftp->write_packet);
9818 + sftp->write_packet = NULL;
9820 + if (sftp->fstat_packet) {
9821 + LIBSSH2_FREE(sftp->channel->session, sftp->fstat_packet);
9822 + sftp->fstat_packet = NULL;
9824 + if (sftp->unlink_packet) {
9825 + LIBSSH2_FREE(sftp->channel->session, sftp->unlink_packet);
9826 + sftp->unlink_packet = NULL;
9828 + if (sftp->rename_packet) {
9829 + LIBSSH2_FREE(sftp->channel->session, sftp->rename_packet);
9830 + sftp->rename_packet = NULL;
9832 + if (sftp->mkdir_packet) {
9833 + LIBSSH2_FREE(sftp->channel->session, sftp->mkdir_packet);
9834 + sftp->mkdir_packet = NULL;
9836 + if (sftp->rmdir_packet) {
9837 + LIBSSH2_FREE(sftp->channel->session, sftp->rmdir_packet);
9838 + sftp->rmdir_packet = NULL;
9840 + if (sftp->stat_packet) {
9841 + LIBSSH2_FREE(sftp->channel->session, sftp->stat_packet);
9842 + sftp->stat_packet = NULL;
9844 + if (sftp->symlink_packet) {
9845 + LIBSSH2_FREE(sftp->channel->session, sftp->symlink_packet);
9846 + sftp->symlink_packet = NULL;
9849 + return libssh2_channel_free(sftp->channel);
9854 +/* *******************************
9855 + * SFTP File and Directory Ops *
9856 + ******************************* */
9858 +/* {{{ libssh2_sftp_open_ex
9860 +LIBSSH2_API LIBSSH2_SFTP_HANDLE *
9861 +libssh2_sftp_open_ex(LIBSSH2_SFTP * sftp, const char *filename,
9862 + unsigned int filename_len, unsigned long flags, long mode,
9865 + LIBSSH2_CHANNEL *channel = sftp->channel;
9866 + LIBSSH2_SESSION *session = channel->session;
9867 + LIBSSH2_SFTP_HANDLE *fp;
9868 + LIBSSH2_SFTP_ATTRIBUTES attrs = {
9869 + LIBSSH2_SFTP_ATTR_PERMISSIONS, 0, 0, 0, 0, 0, 0
9871 + unsigned long data_len;
9872 + unsigned char *data, *s;
9873 + static const unsigned char fopen_responses[2] =
9874 + { SSH_FXP_HANDLE, SSH_FXP_STATUS };
9877 + if (sftp->open_state == libssh2_NB_state_idle) {
9878 + /* packet_len(4) + packet_type(1) + request_id(4) + filename_len(4) +
9880 + sftp->open_packet_len = filename_len + 13 +
9882 + LIBSSH2_SFTP_OPENFILE) ? (4 +
9883 + libssh2_sftp_attrsize(&attrs)) : 0);
9885 + s = sftp->open_packet = LIBSSH2_ALLOC(session, sftp->open_packet_len);
9886 + if (!sftp->open_packet) {
9887 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
9888 + "Unable to allocate memory for FXP_OPEN or "
9889 + "FXP_OPENDIR packet",
9893 + /* Filetype in SFTP 3 and earlier */
9894 + attrs.permissions = mode |
9896 + LIBSSH2_SFTP_OPENFILE) ? LIBSSH2_SFTP_ATTR_PFILETYPE_FILE :
9897 + LIBSSH2_SFTP_ATTR_PFILETYPE_DIR);
9899 + libssh2_htonu32(s, sftp->open_packet_len - 4);
9903 + LIBSSH2_SFTP_OPENFILE) ? SSH_FXP_OPEN : SSH_FXP_OPENDIR;
9904 + sftp->open_request_id = sftp->request_id++;
9905 + libssh2_htonu32(s, sftp->open_request_id);
9907 + libssh2_htonu32(s, filename_len);
9909 + memcpy(s, filename, filename_len);
9910 + s += filename_len;
9911 + if (open_type == LIBSSH2_SFTP_OPENFILE) {
9912 + libssh2_htonu32(s, flags);
9914 + s += libssh2_sftp_attr2bin(s, &attrs);
9917 + _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Sending %s open request",
9919 + LIBSSH2_SFTP_OPENFILE) ? "file" : "directory");
9921 + sftp->open_state = libssh2_NB_state_created;
9924 + if (sftp->open_state == libssh2_NB_state_created) {
9925 + rc = libssh2_channel_write_ex(channel, 0, (char *) sftp->open_packet,
9926 + sftp->open_packet_len);
9927 + if (rc == PACKET_EAGAIN) {
9928 + libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
9929 + "Would block sending FXP_OPEN or FXP_OPENDIR command",
9933 + else if (sftp->open_packet_len != rc) {
9934 + /* TODO: partial writes should be fine too and is not a sign of
9935 + an error when in non-blocking mode! */
9937 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
9938 + "Unable to send FXP_OPEN or FXP_OPENDIR command", 0);
9939 + LIBSSH2_FREE(session, sftp->open_packet);
9940 + sftp->open_packet = NULL;
9941 + sftp->open_state = libssh2_NB_state_idle;
9944 + LIBSSH2_FREE(session, sftp->open_packet);
9945 + sftp->open_packet = NULL;
9947 + sftp->open_state = libssh2_NB_state_sent;
9950 + if (sftp->open_state == libssh2_NB_state_sent) {
9951 + rc = sftp_packet_requirev(sftp, 2, fopen_responses,
9952 + sftp->open_request_id, &data,
9954 + if (rc == PACKET_EAGAIN) {
9955 + libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
9956 + "Would block waiting for status message", 0);
9960 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
9961 + "Timeout waiting for status message", 0);
9962 + sftp->open_state = libssh2_NB_state_idle;
9967 + sftp->open_state = libssh2_NB_state_idle;
9969 + /* OPEN can basically get STATUS or HANDLE back, where HANDLE implies a
9970 + fine response while STATUS means error. It seems though that at times
9971 + we get an SSH_FX_OK back in a STATUS, followed the "real" HANDLE so
9972 + we need to properly deal with that. */
9973 + if (data[0] == SSH_FXP_STATUS) {
9975 + sftp->last_errno = libssh2_ntohu32(data + 5);
9977 + if(LIBSSH2_FX_OK == sftp->last_errno) {
9978 + _libssh2_debug(session, LIBSSH2_DBG_SFTP, "got HANDLE FXOK!");
9980 + /* silly situation, but check for a HANDLE */
9981 + rc = sftp_packet_require(sftp, SSH_FXP_HANDLE,
9982 + sftp->open_request_id, &data, &data_len);
9983 + if(rc == PACKET_EAGAIN) {
9984 + /* go back to sent state and wait for something else */
9985 + sftp->open_state = libssh2_NB_state_sent;
9989 + /* we got the handle so this is not a bad situation */
9994 + libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
9995 + "Failed opening remote file", 0);
9996 + _libssh2_debug(session, LIBSSH2_DBG_SFTP, "got FXP_STATUS %d",
9997 + sftp->last_errno);
9998 + LIBSSH2_FREE(session, data);
10003 + fp = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_SFTP_HANDLE));
10005 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
10006 + "Unable to allocate new SFTP handle structure", 0);
10007 + LIBSSH2_FREE(session, data);
10010 + memset(fp, 0, sizeof(LIBSSH2_SFTP_HANDLE));
10011 + fp->handle_type =
10013 + LIBSSH2_SFTP_OPENFILE) ? LIBSSH2_SFTP_HANDLE_FILE :
10014 + LIBSSH2_SFTP_HANDLE_DIR;
10016 + fp->handle_len = libssh2_ntohu32(data + 5);
10017 + if (fp->handle_len > SFTP_HANDLE_MAXLEN) {
10018 + /* SFTP doesn't allow handles longer than 256 characters */
10019 + fp->handle_len = SFTP_HANDLE_MAXLEN;
10022 + memcpy(fp->handle, data + 9, fp->handle_len);
10023 + LIBSSH2_FREE(session, data);
10025 + /* Link the file and the sftp session together */
10026 + fp->next = sftp->handles;
10028 + fp->next->prev = fp;
10032 + fp->u.file.offset = 0;
10034 + _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Open command successful");
10040 +/* {{{ libssh2_sftp_read
10041 + * Read from an SFTP file handle
10043 +LIBSSH2_API ssize_t
10044 +libssh2_sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer,
10045 + size_t buffer_maxlen)
10047 + LIBSSH2_SFTP *sftp = handle->sftp;
10048 + LIBSSH2_CHANNEL *channel = sftp->channel;
10049 + LIBSSH2_SESSION *session = channel->session;
10050 + unsigned long data_len, request_id = 0;
10051 + /* 25 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) +
10052 + offset(8) + length(4) */
10053 + ssize_t packet_len = handle->handle_len + 25;
10054 + unsigned char *packet, *s, *data;
10055 + static const unsigned char read_responses[2] =
10056 + { SSH_FXP_DATA, SSH_FXP_STATUS };
10057 + size_t bytes_read = 0;
10058 + size_t bytes_requested = 0;
10059 + size_t total_read = 0;
10062 + if (sftp->read_state == libssh2_NB_state_idle) {
10063 + _libssh2_debug(session, LIBSSH2_DBG_SFTP,
10064 + "Reading %lu bytes from SFTP handle",
10065 + (unsigned long) buffer_maxlen);
10066 + packet = handle->request_packet;
10067 + sftp->read_state = libssh2_NB_state_allocated;
10069 + packet = sftp->read_packet;
10070 + request_id = sftp->read_request_id;
10071 + total_read = sftp->read_total_read;
10074 + while (total_read < buffer_maxlen) {
10077 + * If buffer_maxlen bytes will be requested, server may return all
10078 + * with one packet. But libssh2 have packet length limit.
10079 + * So we request data by pieces.
10081 + bytes_requested = buffer_maxlen - total_read;
10082 + /* 10 = packet_type(1) + request_id(4) + data_length(4) +
10083 + end_of_line_flag(1)
10085 + 10 is changed to 13 below simple because it seems there's a
10086 + "GlobalScape" SFTP server that responds with a slightly too big
10087 + buffer at times and we can apparently compensate for that by doing
10090 + Further details on this issue:
10092 + https://sourceforge.net/mailarchive/forum.php?thread_name=9c3275a90811261517v6c0b1da2u918cc1b8370abf83%40mail.gmail.com&forum_name=libssh2-devel
10094 + http://forums.globalscape.com/tm.aspx?m=15249
10097 + if (bytes_requested > LIBSSH2_SFTP_PACKET_MAXLEN - 13) {
10098 + bytes_requested = LIBSSH2_SFTP_PACKET_MAXLEN - 13;
10100 +#ifdef LIBSSH2_DEBUG_SFTP
10101 + _libssh2_debug(session, LIBSSH2_DBG_SFTP,
10102 + "Requesting %lu bytes from SFTP handle",
10103 + (unsigned long) bytes_requested);
10106 + if (sftp->read_state == libssh2_NB_state_allocated) {
10107 + libssh2_htonu32(s, packet_len - 4);
10109 + *(s++) = SSH_FXP_READ;
10110 + request_id = sftp->request_id++;
10111 + libssh2_htonu32(s, request_id);
10113 + libssh2_htonu32(s, handle->handle_len);
10116 + memcpy(s, handle->handle, handle->handle_len);
10117 + s += handle->handle_len;
10119 + libssh2_htonu64(s, handle->u.file.offset);
10122 + libssh2_htonu32(s, bytes_requested);
10125 + sftp->read_state = libssh2_NB_state_created;
10128 + if (sftp->read_state == libssh2_NB_state_created) {
10130 + libssh2_channel_write_ex(channel, 0, (char *) packet,
10132 + if (retcode == PACKET_EAGAIN) {
10133 + sftp->read_packet = packet;
10134 + sftp->read_request_id = request_id;
10135 + sftp->read_total_read = total_read;
10136 + return PACKET_EAGAIN;
10137 + } else if (packet_len != retcode) {
10138 + /* TODO: a partial write is not a critical error when in
10139 + non-blocking mode! */
10140 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
10141 + "Unable to send FXP_READ command", 0);
10142 + sftp->read_packet = NULL;
10143 + sftp->read_state = libssh2_NB_state_idle;
10146 + sftp->read_packet = packet;
10147 + sftp->read_request_id = request_id;
10148 + sftp->read_total_read = total_read;
10149 + sftp->read_state = libssh2_NB_state_sent;
10152 + if (sftp->read_state == libssh2_NB_state_sent) {
10154 + sftp_packet_requirev(sftp, 2, read_responses,
10155 + request_id, &data, &data_len);
10156 + if (retcode == PACKET_EAGAIN) {
10157 + return PACKET_EAGAIN;
10158 + } else if (retcode) {
10159 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
10160 + "Timeout waiting for status message", 0);
10161 + sftp->read_packet = NULL;
10162 + sftp->read_state = libssh2_NB_state_idle;
10166 + sftp->read_state = libssh2_NB_state_sent1;
10169 + switch (data[0]) {
10170 + case SSH_FXP_STATUS:
10171 + retcode = libssh2_ntohu32(data + 5);
10172 + LIBSSH2_FREE(session, data);
10173 + sftp->read_packet = NULL;
10174 + sftp->read_state = libssh2_NB_state_idle;
10176 + if (retcode == LIBSSH2_FX_EOF) {
10177 + return total_read;
10179 + sftp->last_errno = retcode;
10180 + libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
10181 + "SFTP Protocol Error", 0);
10185 + case SSH_FXP_DATA:
10186 + bytes_read = libssh2_ntohu32(data + 5);
10187 + if (bytes_read > (data_len - 9)) {
10188 + sftp->read_packet = NULL;
10189 + sftp->read_state = libssh2_NB_state_idle;
10192 +#ifdef LIBSSH2_DEBUG_SFTP
10193 + _libssh2_debug(session, LIBSSH2_DBG_SFTP, "%lu bytes returned",
10194 + (unsigned long) bytes_read);
10196 + memcpy(buffer + total_read, data + 9, bytes_read);
10197 + handle->u.file.offset += bytes_read;
10198 + total_read += bytes_read;
10199 + LIBSSH2_FREE(session, data);
10201 + * Set the state back to allocated, so a new one will be
10202 + * created to either request more data or get EOF
10204 + sftp->read_state = libssh2_NB_state_allocated;
10208 + sftp->read_packet = NULL;
10209 + sftp->read_state = libssh2_NB_state_idle;
10210 + return total_read;
10215 +/* {{{ libssh2_sftp_readdir
10216 + * Read from an SFTP directory handle
10219 +libssh2_sftp_readdir_ex(LIBSSH2_SFTP_HANDLE * handle, char *buffer,
10220 + size_t buffer_maxlen, char *longentry,
10221 + size_t longentry_maxlen,
10222 + LIBSSH2_SFTP_ATTRIBUTES * attrs)
10224 + LIBSSH2_SFTP *sftp = handle->sftp;
10225 + LIBSSH2_CHANNEL *channel = sftp->channel;
10226 + LIBSSH2_SESSION *session = channel->session;
10227 + LIBSSH2_SFTP_ATTRIBUTES attrs_dummy;
10228 + unsigned long data_len, filename_len, longentry_len, num_names;
10229 + /* 13 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) */
10230 + ssize_t packet_len = handle->handle_len + 13;
10231 + unsigned char *s, *data;
10232 + unsigned char read_responses[2] = { SSH_FXP_NAME, SSH_FXP_STATUS };
10235 + if (sftp->readdir_state == libssh2_NB_state_idle) {
10236 + if (handle->u.dir.names_left) {
10238 + * A prior request returned more than one directory entry,
10239 + * feed it back from the buffer
10241 + unsigned char *s = (unsigned char *) handle->u.dir.next_name;
10242 + unsigned long real_filename_len = libssh2_ntohu32(s);
10244 + filename_len = real_filename_len;
10246 + if (filename_len > buffer_maxlen) {
10247 + filename_len = buffer_maxlen;
10249 + memcpy(buffer, s, filename_len);
10250 + s += real_filename_len;
10252 + /* The filename is not null terminated, make it so if possible */
10253 + if (filename_len < buffer_maxlen) {
10254 + buffer[filename_len] = '\0';
10257 + if ((longentry == NULL) || (longentry_maxlen == 0)) {
10258 + /* Skip longname */
10259 + s += 4 + libssh2_ntohu32(s);
10261 + unsigned long real_longentry_len = libssh2_ntohu32(s);
10263 + longentry_len = real_longentry_len;
10265 + if (longentry_len > longentry_maxlen) {
10266 + longentry_len = longentry_maxlen;
10268 + memcpy(longentry, s, longentry_len);
10269 + s += real_longentry_len;
10271 + /* The longentry is not null terminated, make it so if possible */
10272 + if (longentry_len < longentry_maxlen) {
10273 + longentry[longentry_len] = '\0';
10278 + memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
10280 + s += libssh2_sftp_bin2attr(attrs ? attrs : &attrs_dummy, s);
10282 + handle->u.dir.next_name = (char *) s;
10283 + if ((--handle->u.dir.names_left) == 0) {
10284 + LIBSSH2_FREE(session, handle->u.dir.names_packet);
10287 + _libssh2_debug(session, LIBSSH2_DBG_SFTP,
10288 + "libssh2_sftp_readdir_ex() return %d",
10290 + return filename_len;
10293 + /* Request another entry(entries?) */
10295 + s = sftp->readdir_packet = LIBSSH2_ALLOC(session, packet_len);
10296 + if (!sftp->readdir_packet) {
10297 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
10298 + "Unable to allocate memory for FXP_READDIR packet",
10303 + libssh2_htonu32(s, packet_len - 4);
10305 + *(s++) = SSH_FXP_READDIR;
10306 + sftp->readdir_request_id = sftp->request_id++;
10307 + libssh2_htonu32(s, sftp->readdir_request_id);
10309 + libssh2_htonu32(s, handle->handle_len);
10311 + memcpy(s, handle->handle, handle->handle_len);
10312 + s += handle->handle_len;
10314 + sftp->readdir_state = libssh2_NB_state_created;
10317 + if (sftp->readdir_state == libssh2_NB_state_created) {
10318 + _libssh2_debug(session, LIBSSH2_DBG_SFTP,
10319 + "Reading entries from directory handle");
10321 + libssh2_channel_write_ex(channel, 0,
10322 + (char *) sftp->readdir_packet,
10323 + packet_len)) == PACKET_EAGAIN) {
10324 + return PACKET_EAGAIN;
10325 + } else if (packet_len != retcode) {
10326 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
10327 + "Unable to send FXP_READ command", 0);
10328 + LIBSSH2_FREE(session, sftp->readdir_packet);
10329 + sftp->readdir_packet = NULL;
10330 + sftp->readdir_state = libssh2_NB_state_idle;
10334 + LIBSSH2_FREE(session, sftp->readdir_packet);
10335 + sftp->readdir_packet = NULL;
10337 + sftp->readdir_state = libssh2_NB_state_sent;
10341 + sftp_packet_requirev(sftp, 2, read_responses,
10342 + sftp->readdir_request_id, &data,
10344 + if (retcode == PACKET_EAGAIN) {
10345 + return PACKET_EAGAIN;
10346 + } else if (retcode) {
10347 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
10348 + "Timeout waiting for status message", 0);
10349 + sftp->readdir_state = libssh2_NB_state_idle;
10353 + if (data[0] == SSH_FXP_STATUS) {
10354 + retcode = libssh2_ntohu32(data + 5);
10355 + LIBSSH2_FREE(session, data);
10356 + if (retcode == LIBSSH2_FX_EOF) {
10357 + sftp->readdir_state = libssh2_NB_state_idle;
10360 + sftp->last_errno = retcode;
10361 + libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
10362 + "SFTP Protocol Error", 0);
10363 + sftp->readdir_state = libssh2_NB_state_idle;
10368 + num_names = libssh2_ntohu32(data + 5);
10369 + _libssh2_debug(session, LIBSSH2_DBG_SFTP, "%lu entries returned",
10371 + if (num_names <= 0) {
10372 + LIBSSH2_FREE(session, data);
10373 + sftp->readdir_state = libssh2_NB_state_idle;
10374 + return (num_names == 0) ? 0 : -1;
10377 + if (num_names == 1) {
10378 + unsigned long real_filename_len = libssh2_ntohu32(data + 9);
10380 + filename_len = real_filename_len;
10381 + if (filename_len > buffer_maxlen) {
10382 + filename_len = buffer_maxlen;
10384 + memcpy(buffer, data + 13, filename_len);
10386 + /* The filename is not null terminated, make it so if possible */
10387 + if (filename_len < buffer_maxlen) {
10388 + buffer[filename_len] = '\0';
10392 + memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
10393 + libssh2_sftp_bin2attr(attrs, data + 13 + real_filename_len +
10395 + libssh2_ntohu32(data + 13 +
10396 + real_filename_len)));
10398 + LIBSSH2_FREE(session, data);
10400 + sftp->readdir_state = libssh2_NB_state_idle;
10401 + return filename_len;
10404 + handle->u.dir.names_left = num_names;
10405 + handle->u.dir.names_packet = data;
10406 + handle->u.dir.next_name = (char *) data + 9;
10408 + sftp->readdir_state = libssh2_NB_state_idle;
10410 + /* Be lazy, just use the name popping mechanism from the start of the function */
10411 + return libssh2_sftp_readdir_ex(handle, buffer, buffer_maxlen, longentry,
10412 + longentry_maxlen, attrs);
10417 +/* {{{ libssh2_sftp_write
10418 + * Write data to a file handle
10420 +LIBSSH2_API ssize_t
10421 +libssh2_sftp_write(LIBSSH2_SFTP_HANDLE * handle, const char *buffer,
10424 + LIBSSH2_SFTP *sftp = handle->sftp;
10425 + LIBSSH2_CHANNEL *channel = sftp->channel;
10426 + LIBSSH2_SESSION *session = channel->session;
10427 + unsigned long data_len, retcode;
10428 + /* 25 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) +
10429 + offset(8) + count(4) */
10430 + ssize_t packet_len = handle->handle_len + count + 25;
10431 + unsigned char *s, *data;
10434 + if (sftp->write_state == libssh2_NB_state_idle) {
10435 + _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Writing %lu bytes",
10436 + (unsigned long) count);
10437 + s = sftp->write_packet = LIBSSH2_ALLOC(session, packet_len);
10438 + if (!sftp->write_packet) {
10439 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
10440 + "Unable to allocate memory for FXP_WRITE packet", 0);
10444 + libssh2_htonu32(s, packet_len - 4);
10446 + *(s++) = SSH_FXP_WRITE;
10447 + sftp->write_request_id = sftp->request_id++;
10448 + libssh2_htonu32(s, sftp->write_request_id);
10450 + libssh2_htonu32(s, handle->handle_len);
10452 + memcpy(s, handle->handle, handle->handle_len);
10453 + s += handle->handle_len;
10454 + libssh2_htonu64(s, handle->u.file.offset);
10456 + libssh2_htonu32(s, count);
10458 + memcpy(s, buffer, count);
10461 + sftp->write_state = libssh2_NB_state_created;
10464 + if (sftp->write_state == libssh2_NB_state_created) {
10466 + libssh2_channel_write_ex(channel, 0, (char *) sftp->write_packet,
10467 + packet_len)) == PACKET_EAGAIN) {
10468 + return PACKET_EAGAIN;
10470 + if (packet_len != rc) {
10471 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
10472 + "Unable to send FXP_READ command", 0);
10473 + LIBSSH2_FREE(session, sftp->write_packet);
10474 + sftp->write_packet = NULL;
10475 + sftp->write_state = libssh2_NB_state_idle;
10478 + LIBSSH2_FREE(session, sftp->write_packet);
10479 + sftp->write_packet = NULL;
10480 + sftp->write_state = libssh2_NB_state_sent;
10483 + rc = sftp_packet_require(sftp, SSH_FXP_STATUS,
10484 + sftp->write_request_id, &data, &data_len);
10485 + if (rc == PACKET_EAGAIN) {
10486 + return PACKET_EAGAIN;
10488 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
10489 + "Timeout waiting for status message", 0);
10490 + sftp->write_state = libssh2_NB_state_idle;
10494 + sftp->write_state = libssh2_NB_state_idle;
10496 + retcode = libssh2_ntohu32(data + 5);
10497 + LIBSSH2_FREE(session, data);
10499 + if (retcode == LIBSSH2_FX_OK) {
10500 + handle->u.file.offset += count;
10503 + libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error",
10505 + sftp->last_errno = retcode;
10512 +/* {{{ libssh2_sftp_fstat_ex
10513 + * Get or Set stat on a file
10516 +libssh2_sftp_fstat_ex(LIBSSH2_SFTP_HANDLE * handle,
10517 + LIBSSH2_SFTP_ATTRIBUTES * attrs, int setstat)
10519 + LIBSSH2_SFTP *sftp = handle->sftp;
10520 + LIBSSH2_CHANNEL *channel = sftp->channel;
10521 + LIBSSH2_SESSION *session = channel->session;
10522 + unsigned long data_len;
10523 + /* 13 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) */
10524 + ssize_t packet_len =
10525 + handle->handle_len + 13 + (setstat ? libssh2_sftp_attrsize(attrs) : 0);
10526 + unsigned char *s, *data;
10527 + static const unsigned char fstat_responses[2] =
10528 + { SSH_FXP_ATTRS, SSH_FXP_STATUS };
10531 + if (sftp->fstat_state == libssh2_NB_state_idle) {
10532 + _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Issuing %s command",
10533 + setstat ? "set-stat" : "stat");
10534 + s = sftp->fstat_packet = LIBSSH2_ALLOC(session, packet_len);
10535 + if (!sftp->fstat_packet) {
10536 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
10537 + "Unable to allocate memory for FSTAT/FSETSTAT packet",
10542 + libssh2_htonu32(s, packet_len - 4);
10544 + *(s++) = setstat ? SSH_FXP_FSETSTAT : SSH_FXP_FSTAT;
10545 + sftp->fstat_request_id = sftp->request_id++;
10546 + libssh2_htonu32(s, sftp->fstat_request_id);
10548 + libssh2_htonu32(s, handle->handle_len);
10550 + memcpy(s, handle->handle, handle->handle_len);
10551 + s += handle->handle_len;
10553 + s += libssh2_sftp_attr2bin(s, attrs);
10556 + sftp->fstat_state = libssh2_NB_state_created;
10559 + if (sftp->fstat_state == libssh2_NB_state_created) {
10560 + rc = libssh2_channel_write_ex(channel, 0, (char *) sftp->fstat_packet,
10562 + if (rc == PACKET_EAGAIN) {
10563 + return PACKET_EAGAIN;
10564 + } else if (packet_len != rc) {
10565 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
10566 + (setstat ? "Unable to send FXP_FSETSTAT"
10567 + : "Unable to send FXP_FSTAT command"), 0);
10568 + LIBSSH2_FREE(session, sftp->fstat_packet);
10569 + sftp->fstat_packet = NULL;
10570 + sftp->fstat_state = libssh2_NB_state_idle;
10573 + LIBSSH2_FREE(session, sftp->fstat_packet);
10574 + sftp->fstat_packet = NULL;
10576 + sftp->fstat_state = libssh2_NB_state_sent;
10579 + rc = sftp_packet_requirev(sftp, 2, fstat_responses,
10580 + sftp->fstat_request_id, &data,
10582 + if (rc == PACKET_EAGAIN) {
10583 + return PACKET_EAGAIN;
10585 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
10586 + "Timeout waiting for status message", 0);
10587 + sftp->fstat_state = libssh2_NB_state_idle;
10591 + sftp->fstat_state = libssh2_NB_state_idle;
10593 + if (data[0] == SSH_FXP_STATUS) {
10596 + retcode = libssh2_ntohu32(data + 5);
10597 + LIBSSH2_FREE(session, data);
10598 + if (retcode == LIBSSH2_FX_OK) {
10601 + sftp->last_errno = retcode;
10602 + libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
10603 + "SFTP Protocol Error", 0);
10608 + libssh2_sftp_bin2attr(attrs, data + 5);
10615 +/* {{{ libssh2_sftp_seek
10616 + * Set the read/write pointer to an arbitrary position within the file
10619 +libssh2_sftp_seek(LIBSSH2_SFTP_HANDLE * handle, size_t offset)
10621 + handle->u.file.offset = offset;
10626 +/* {{{ libssh2_sftp_seek64
10627 + * Set the read/write pointer to an arbitrary position within the file
10630 +libssh2_sftp_seek64(LIBSSH2_SFTP_HANDLE * handle, libssh2_uint64_t offset)
10632 + handle->u.file.offset = offset;
10637 +/* {{{ libssh2_sftp_tell
10638 + * Return the current read/write pointer's offset
10640 +LIBSSH2_API size_t
10641 +libssh2_sftp_tell(LIBSSH2_SFTP_HANDLE * handle)
10643 + return handle->u.file.offset;
10646 +/* {{{ libssh2_sftp_tell64
10647 + * Return the current read/write pointer's offset
10649 +LIBSSH2_API libssh2_uint64_t
10650 +libssh2_sftp_tell64(LIBSSH2_SFTP_HANDLE * handle)
10652 + return handle->u.file.offset;
10658 +/* {{{ libssh2_sftp_close_handle
10659 + * Close a file or directory handle
10660 + * Also frees handle resource and unlinks it from the SFTP structure
10663 +libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE * handle)
10665 + LIBSSH2_SFTP *sftp = handle->sftp;
10666 + LIBSSH2_CHANNEL *channel = sftp->channel;
10667 + LIBSSH2_SESSION *session = channel->session;
10668 + unsigned long data_len, retcode;
10669 + /* 13 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) */
10670 + ssize_t packet_len = handle->handle_len + 13;
10671 + unsigned char *s, *data;
10674 + if (handle->close_state == libssh2_NB_state_idle) {
10675 + _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Closing handle");
10676 + s = handle->close_packet = LIBSSH2_ALLOC(session, packet_len);
10677 + if (!handle->close_packet) {
10678 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
10679 + "Unable to allocate memory for FXP_CLOSE packet", 0);
10683 + libssh2_htonu32(s, packet_len - 4);
10685 + *(s++) = SSH_FXP_CLOSE;
10686 + handle->close_request_id = sftp->request_id++;
10687 + libssh2_htonu32(s, handle->close_request_id);
10689 + libssh2_htonu32(s, handle->handle_len);
10691 + memcpy(s, handle->handle, handle->handle_len);
10692 + s += handle->handle_len;
10694 + handle->close_state = libssh2_NB_state_created;
10697 + if (handle->close_state == libssh2_NB_state_created) {
10698 + rc = libssh2_channel_write_ex(channel, 0,
10699 + (char *) handle->close_packet,
10701 + if (rc == PACKET_EAGAIN) {
10702 + return PACKET_EAGAIN;
10703 + } else if (packet_len != rc) {
10704 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
10705 + "Unable to send FXP_CLOSE command", 0);
10706 + LIBSSH2_FREE(session, handle->close_packet);
10707 + handle->close_packet = NULL;
10708 + handle->close_state = libssh2_NB_state_idle;
10711 + LIBSSH2_FREE(session, handle->close_packet);
10712 + handle->close_packet = NULL;
10714 + handle->close_state = libssh2_NB_state_sent;
10717 + if (handle->close_state == libssh2_NB_state_sent) {
10718 + rc = sftp_packet_require(sftp, SSH_FXP_STATUS,
10719 + handle->close_request_id, &data,
10721 + if (rc == PACKET_EAGAIN) {
10722 + return PACKET_EAGAIN;
10724 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
10725 + "Timeout waiting for status message", 0);
10726 + handle->close_state = libssh2_NB_state_idle;
10730 + handle->close_state = libssh2_NB_state_sent1;
10733 + retcode = libssh2_ntohu32(data + 5);
10734 + LIBSSH2_FREE(session, data);
10736 + if (retcode != LIBSSH2_FX_OK) {
10737 + sftp->last_errno = retcode;
10738 + libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
10739 + "SFTP Protocol Error", 0);
10740 + handle->close_state = libssh2_NB_state_idle;
10744 + if (handle == sftp->handles) {
10745 + sftp->handles = handle->next;
10747 + if (handle->next) {
10748 + handle->next->prev = NULL;
10751 + if ((handle->handle_type == LIBSSH2_SFTP_HANDLE_DIR)
10752 + && handle->u.dir.names_left) {
10753 + LIBSSH2_FREE(session, handle->u.dir.names_packet);
10756 + handle->close_state = libssh2_NB_state_idle;
10758 + LIBSSH2_FREE(session, handle);
10765 +/* **********************
10766 + * SFTP Miscellaneous *
10767 + ********************** */
10769 +/* {{{ libssh2_sftp_unlink_ex
10770 + * Delete a file from the remote server
10772 +/* libssh2_sftp_unlink_ex - NB-UNSAFE?? */
10774 +libssh2_sftp_unlink_ex(LIBSSH2_SFTP * sftp, const char *filename,
10775 + unsigned int filename_len)
10777 + LIBSSH2_CHANNEL *channel = sftp->channel;
10778 + LIBSSH2_SESSION *session = channel->session;
10779 + unsigned long data_len, retcode;
10780 + /* 13 = packet_len(4) + packet_type(1) + request_id(4) + filename_len(4) */
10781 + ssize_t packet_len = filename_len + 13;
10782 + unsigned char *s, *data;
10785 + if (sftp->unlink_state == libssh2_NB_state_idle) {
10786 + _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Unlinking %s", filename);
10787 + s = sftp->unlink_packet = LIBSSH2_ALLOC(session, packet_len);
10788 + if (!sftp->unlink_packet) {
10789 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
10790 + "Unable to allocate memory for FXP_REMOVE packet",
10795 + libssh2_htonu32(s, packet_len - 4);
10797 + *(s++) = SSH_FXP_REMOVE;
10798 + sftp->unlink_request_id = sftp->request_id++;
10799 + libssh2_htonu32(s, sftp->unlink_request_id);
10801 + libssh2_htonu32(s, filename_len);
10803 + memcpy(s, filename, filename_len);
10804 + s += filename_len;
10806 + sftp->unlink_state = libssh2_NB_state_created;
10809 + if (sftp->unlink_state == libssh2_NB_state_created) {
10810 + rc = libssh2_channel_write_ex(channel, 0, (char *) sftp->unlink_packet,
10812 + if (rc == PACKET_EAGAIN) {
10813 + return PACKET_EAGAIN;
10814 + } else if (packet_len != rc) {
10815 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
10816 + "Unable to send FXP_REMOVE command", 0);
10817 + LIBSSH2_FREE(session, sftp->unlink_packet);
10818 + sftp->unlink_packet = NULL;
10819 + sftp->unlink_state = libssh2_NB_state_idle;
10822 + LIBSSH2_FREE(session, sftp->unlink_packet);
10823 + sftp->unlink_packet = NULL;
10825 + sftp->unlink_state = libssh2_NB_state_sent;
10828 + rc = sftp_packet_require(sftp, SSH_FXP_STATUS,
10829 + sftp->unlink_request_id, &data,
10831 + if (rc == PACKET_EAGAIN) {
10832 + return PACKET_EAGAIN;
10835 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
10836 + "Timeout waiting for status message", 0);
10837 + sftp->unlink_state = libssh2_NB_state_idle;
10841 + sftp->unlink_state = libssh2_NB_state_idle;
10843 + retcode = libssh2_ntohu32(data + 5);
10844 + LIBSSH2_FREE(session, data);
10846 + if (retcode == LIBSSH2_FX_OK) {
10849 + sftp->last_errno = retcode;
10850 + libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
10851 + "SFTP Protocol Error", 0);
10858 +/* {{{ libssh2_sftp_rename_ex
10859 + * Rename a file on the remote server
10862 +libssh2_sftp_rename_ex(LIBSSH2_SFTP * sftp, const char *source_filename,
10863 + unsigned int source_filename_len,
10864 + const char *dest_filename,
10865 + unsigned int dest_filename_len, long flags)
10867 + LIBSSH2_CHANNEL *channel = sftp->channel;
10868 + LIBSSH2_SESSION *session = channel->session;
10869 + unsigned long data_len, retcode;
10870 + ssize_t packet_len =
10871 + source_filename_len + dest_filename_len + 17 + (sftp->version >=
10873 + /* packet_len(4) + packet_type(1) + request_id(4) +
10874 + source_filename_len(4) + dest_filename_len(4) + flags(4){SFTP5+) */
10875 + unsigned char *data;
10878 + if (sftp->version < 2) {
10879 + libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
10880 + "Server does not support RENAME", 0);
10884 + if (sftp->rename_state == libssh2_NB_state_idle) {
10885 + _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Renaming %s to %s",
10886 + source_filename, dest_filename);
10887 + sftp->rename_s = sftp->rename_packet =
10888 + LIBSSH2_ALLOC(session, packet_len);
10889 + if (!sftp->rename_packet) {
10890 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
10891 + "Unable to allocate memory for FXP_RENAME packet",
10896 + libssh2_htonu32(sftp->rename_s, packet_len - 4);
10897 + sftp->rename_s += 4;
10898 + *(sftp->rename_s++) = SSH_FXP_RENAME;
10899 + sftp->rename_request_id = sftp->request_id++;
10900 + libssh2_htonu32(sftp->rename_s, sftp->rename_request_id);
10901 + sftp->rename_s += 4;
10902 + libssh2_htonu32(sftp->rename_s, source_filename_len);
10903 + sftp->rename_s += 4;
10904 + memcpy(sftp->rename_s, source_filename, source_filename_len);
10905 + sftp->rename_s += source_filename_len;
10906 + libssh2_htonu32(sftp->rename_s, dest_filename_len);
10907 + sftp->rename_s += 4;
10908 + memcpy(sftp->rename_s, dest_filename, dest_filename_len);
10909 + sftp->rename_s += dest_filename_len;
10911 + if (sftp->version >= 5) {
10912 + libssh2_htonu32(sftp->rename_s, flags);
10913 + sftp->rename_s += 4;
10916 + sftp->rename_state = libssh2_NB_state_created;
10919 + if (sftp->rename_state == libssh2_NB_state_created) {
10920 + rc = libssh2_channel_write_ex(channel, 0, (char *) sftp->rename_packet,
10921 + sftp->rename_s - sftp->rename_packet);
10922 + if (rc == PACKET_EAGAIN) {
10923 + return PACKET_EAGAIN;
10924 + } else if (packet_len != rc) {
10925 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
10926 + "Unable to send FXP_RENAME command", 0);
10927 + LIBSSH2_FREE(session, sftp->rename_packet);
10928 + sftp->rename_packet = NULL;
10929 + sftp->rename_state = libssh2_NB_state_idle;
10932 + LIBSSH2_FREE(session, sftp->rename_packet);
10933 + sftp->rename_packet = NULL;
10935 + sftp->rename_state = libssh2_NB_state_sent;
10938 + rc = sftp_packet_require(sftp, SSH_FXP_STATUS,
10939 + sftp->rename_request_id, &data,
10941 + if (rc == PACKET_EAGAIN) {
10942 + return PACKET_EAGAIN;
10944 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
10945 + "Timeout waiting for status message", 0);
10946 + sftp->rename_state = libssh2_NB_state_idle;
10950 + sftp->rename_state = libssh2_NB_state_idle;
10952 + retcode = libssh2_ntohu32(data + 5);
10953 + LIBSSH2_FREE(session, data);
10955 + switch (retcode) {
10956 + case LIBSSH2_FX_OK:
10960 + case LIBSSH2_FX_FILE_ALREADY_EXISTS:
10961 + libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
10962 + "File already exists and SSH_FXP_RENAME_OVERWRITE not specified",
10964 + sftp->last_errno = retcode;
10968 + case LIBSSH2_FX_OP_UNSUPPORTED:
10969 + libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
10970 + "Operation Not Supported", 0);
10971 + sftp->last_errno = retcode;
10976 + libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
10977 + "SFTP Protocol Error", 0);
10978 + sftp->last_errno = retcode;
10987 +/* {{{ libssh2_sftp_mkdir_ex
10988 + * Create an SFTP directory
10991 +libssh2_sftp_mkdir_ex(LIBSSH2_SFTP * sftp, const char *path,
10992 + unsigned int path_len, long mode)
10994 + LIBSSH2_CHANNEL *channel = sftp->channel;
10995 + LIBSSH2_SESSION *session = channel->session;
10996 + LIBSSH2_SFTP_ATTRIBUTES attrs = {
10997 + LIBSSH2_SFTP_ATTR_PERMISSIONS, 0, 0, 0, 0, 0, 0
10999 + unsigned long data_len, retcode, request_id;
11000 + /* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */
11001 + ssize_t packet_len = path_len + 13 + libssh2_sftp_attrsize(&attrs);
11002 + unsigned char *packet, *s, *data;
11005 + if (sftp->mkdir_state == libssh2_NB_state_idle) {
11006 + _libssh2_debug(session, LIBSSH2_DBG_SFTP,
11007 + "Creating directory %s with mode 0%lo", path, mode);
11008 + s = packet = LIBSSH2_ALLOC(session, packet_len);
11010 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
11011 + "Unable to allocate memory for FXP_MKDIR packet", 0);
11014 + /* Filetype in SFTP 3 and earlier */
11015 + attrs.permissions = mode | LIBSSH2_SFTP_ATTR_PFILETYPE_DIR;
11017 + libssh2_htonu32(s, packet_len - 4);
11019 + *(s++) = SSH_FXP_MKDIR;
11020 + request_id = sftp->request_id++;
11021 + libssh2_htonu32(s, request_id);
11023 + libssh2_htonu32(s, path_len);
11025 + memcpy(s, path, path_len);
11027 + s += libssh2_sftp_attr2bin(s, &attrs);
11029 + sftp->mkdir_state = libssh2_NB_state_created;
11031 + packet = sftp->mkdir_packet;
11032 + request_id = sftp->mkdir_request_id;
11035 + if (sftp->mkdir_state == libssh2_NB_state_created) {
11036 + rc = libssh2_channel_write_ex(channel, 0, (char *) packet, packet_len);
11037 + if (rc == PACKET_EAGAIN) {
11038 + sftp->mkdir_packet = packet;
11039 + sftp->mkdir_request_id = request_id;
11040 + return PACKET_EAGAIN;
11042 + if (packet_len != rc) {
11043 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
11044 + "Unable to send FXP_READ command", 0);
11045 + LIBSSH2_FREE(session, packet);
11046 + sftp->mkdir_state = libssh2_NB_state_idle;
11049 + LIBSSH2_FREE(session, packet);
11050 + sftp->mkdir_state = libssh2_NB_state_sent;
11051 + sftp->mkdir_packet = NULL;
11054 + rc = sftp_packet_require(sftp, SSH_FXP_STATUS, request_id, &data,
11056 + if (rc == PACKET_EAGAIN) {
11057 + return PACKET_EAGAIN;
11059 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
11060 + "Timeout waiting for status message", 0);
11061 + sftp->mkdir_state = libssh2_NB_state_idle;
11065 + sftp->mkdir_state = libssh2_NB_state_idle;
11067 + retcode = libssh2_ntohu32(data + 5);
11068 + LIBSSH2_FREE(session, data);
11070 + if (retcode == LIBSSH2_FX_OK) {
11073 + libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
11074 + "SFTP Protocol Error", 0);
11075 + sftp->last_errno = retcode;
11082 +/* {{{ libssh2_sftp_rmdir_ex
11083 + * Remove a directory
11085 +/* libssh2_sftp_rmdir_ex - NB-UNSAFE?? */
11087 +libssh2_sftp_rmdir_ex(LIBSSH2_SFTP * sftp, const char *path,
11088 + unsigned int path_len)
11090 + LIBSSH2_CHANNEL *channel = sftp->channel;
11091 + LIBSSH2_SESSION *session = channel->session;
11092 + unsigned long data_len, retcode;
11093 + /* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */
11094 + ssize_t packet_len = path_len + 13;
11095 + unsigned char *s, *data;
11098 + if (sftp->rmdir_state == libssh2_NB_state_idle) {
11099 + _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Removing directory: %s",
11101 + s = sftp->rmdir_packet = LIBSSH2_ALLOC(session, packet_len);
11102 + if (!sftp->rmdir_packet) {
11103 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
11104 + "Unable to allocate memory for FXP_MKDIR packet", 0);
11108 + libssh2_htonu32(s, packet_len - 4);
11110 + *(s++) = SSH_FXP_RMDIR;
11111 + sftp->rmdir_request_id = sftp->request_id++;
11112 + libssh2_htonu32(s, sftp->rmdir_request_id);
11114 + libssh2_htonu32(s, path_len);
11116 + memcpy(s, path, path_len);
11119 + sftp->rmdir_state = libssh2_NB_state_created;
11122 + if (sftp->rmdir_state == libssh2_NB_state_created) {
11123 + rc = libssh2_channel_write_ex(channel, 0, (char *) sftp->rmdir_packet,
11125 + if (rc == PACKET_EAGAIN) {
11126 + return PACKET_EAGAIN;
11127 + } else if (packet_len != rc) {
11128 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
11129 + "Unable to send FXP_MKDIR command", 0);
11130 + LIBSSH2_FREE(session, sftp->rmdir_packet);
11131 + sftp->rmdir_packet = NULL;
11132 + sftp->rmdir_state = libssh2_NB_state_idle;
11135 + LIBSSH2_FREE(session, sftp->rmdir_packet);
11136 + sftp->rmdir_packet = NULL;
11138 + sftp->rmdir_state = libssh2_NB_state_sent;
11141 + rc = sftp_packet_require(sftp, SSH_FXP_STATUS,
11142 + sftp->rmdir_request_id, &data, &data_len);
11143 + if (rc == PACKET_EAGAIN) {
11144 + return PACKET_EAGAIN;
11146 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
11147 + "Timeout waiting for status message", 0);
11148 + sftp->rmdir_state = libssh2_NB_state_idle;
11152 + sftp->rmdir_state = libssh2_NB_state_idle;
11154 + retcode = libssh2_ntohu32(data + 5);
11155 + LIBSSH2_FREE(session, data);
11157 + if (retcode == LIBSSH2_FX_OK) {
11160 + sftp->last_errno = retcode;
11161 + libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
11162 + "SFTP Protocol Error", 0);
11169 +/* {{{ libssh2_sftp_stat_ex
11170 + * Stat a file or symbolic link
11172 +/* libssh2_sftp_stat_ex - NB-UNSAFE?? */
11174 +libssh2_sftp_stat_ex(LIBSSH2_SFTP * sftp, const char *path,
11175 + unsigned int path_len, int stat_type,
11176 + LIBSSH2_SFTP_ATTRIBUTES * attrs)
11178 + LIBSSH2_CHANNEL *channel = sftp->channel;
11179 + LIBSSH2_SESSION *session = channel->session;
11180 + unsigned long data_len;
11181 + /* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */
11182 + ssize_t packet_len =
11185 + LIBSSH2_SFTP_SETSTAT) ? libssh2_sftp_attrsize(attrs) : 0);
11186 + unsigned char *s, *data;
11187 + static const unsigned char stat_responses[2] =
11188 + { SSH_FXP_ATTRS, SSH_FXP_STATUS };
11191 + if (sftp->stat_state == libssh2_NB_state_idle) {
11192 + _libssh2_debug(session, LIBSSH2_DBG_SFTP, "%s %s",
11193 + (stat_type == LIBSSH2_SFTP_SETSTAT) ? "Set-statting" :
11195 + LIBSSH2_SFTP_LSTAT ? "LStatting" : "Statting"), path);
11196 + s = sftp->stat_packet = LIBSSH2_ALLOC(session, packet_len);
11197 + if (!sftp->stat_packet) {
11198 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
11199 + "Unable to allocate memory for FXP_MKDIR packet", 0);
11203 + libssh2_htonu32(s, packet_len - 4);
11205 + switch (stat_type) {
11206 + case LIBSSH2_SFTP_SETSTAT:
11207 + *(s++) = SSH_FXP_SETSTAT;
11210 + case LIBSSH2_SFTP_LSTAT:
11211 + *(s++) = SSH_FXP_LSTAT;
11214 + case LIBSSH2_SFTP_STAT:
11216 + *(s++) = SSH_FXP_STAT;
11218 + sftp->stat_request_id = sftp->request_id++;
11219 + libssh2_htonu32(s, sftp->stat_request_id);
11221 + libssh2_htonu32(s, path_len);
11223 + memcpy(s, path, path_len);
11225 + if (stat_type == LIBSSH2_SFTP_SETSTAT) {
11226 + s += libssh2_sftp_attr2bin(s, attrs);
11229 + sftp->stat_state = libssh2_NB_state_created;
11232 + if (sftp->stat_state == libssh2_NB_state_created) {
11233 + rc = libssh2_channel_write_ex(channel, 0, (char *) sftp->stat_packet,
11235 + if (rc == PACKET_EAGAIN) {
11236 + return PACKET_EAGAIN;
11237 + } else if (packet_len != rc) {
11238 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
11239 + "Unable to send STAT/LSTAT/SETSTAT command", 0);
11240 + LIBSSH2_FREE(session, sftp->stat_packet);
11241 + sftp->stat_packet = NULL;
11242 + sftp->stat_state = libssh2_NB_state_idle;
11245 + LIBSSH2_FREE(session, sftp->stat_packet);
11246 + sftp->stat_packet = NULL;
11248 + sftp->stat_state = libssh2_NB_state_sent;
11251 + rc = sftp_packet_requirev(sftp, 2, stat_responses,
11252 + sftp->stat_request_id, &data, &data_len);
11253 + if (rc == PACKET_EAGAIN) {
11254 + return PACKET_EAGAIN;
11256 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
11257 + "Timeout waiting for status message", 0);
11258 + sftp->stat_state = libssh2_NB_state_idle;
11262 + sftp->stat_state = libssh2_NB_state_idle;
11264 + if (data[0] == SSH_FXP_STATUS) {
11267 + retcode = libssh2_ntohu32(data + 5);
11268 + LIBSSH2_FREE(session, data);
11269 + if (retcode == LIBSSH2_FX_OK) {
11272 + sftp->last_errno = retcode;
11273 + libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
11274 + "SFTP Protocol Error", 0);
11279 + memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
11280 + libssh2_sftp_bin2attr(attrs, data + 5);
11281 + LIBSSH2_FREE(session, data);
11288 +/* {{{ libssh2_sftp_symlink_ex
11289 + * Read or set a symlink
11292 +libssh2_sftp_symlink_ex(LIBSSH2_SFTP * sftp, const char *path,
11293 + unsigned int path_len, char *target,
11294 + unsigned int target_len, int link_type)
11296 + LIBSSH2_CHANNEL *channel = sftp->channel;
11297 + LIBSSH2_SESSION *session = channel->session;
11298 + unsigned long data_len, link_len;
11299 + /* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */
11300 + ssize_t packet_len =
11302 + ((link_type == LIBSSH2_SFTP_SYMLINK) ? (4 + target_len) : 0);
11303 + unsigned char *s, *data;
11304 + static const unsigned char link_responses[2] =
11305 + { SSH_FXP_NAME, SSH_FXP_STATUS };
11308 + if ((sftp->version < 3) && (link_type != LIBSSH2_SFTP_REALPATH)) {
11309 + libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
11310 + "Server does not support SYMLINK or READLINK", 0);
11314 + if (sftp->symlink_state == libssh2_NB_state_idle) {
11315 + s = sftp->symlink_packet = LIBSSH2_ALLOC(session, packet_len);
11316 + if (!sftp->symlink_packet) {
11317 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
11318 + "Unable to allocate memory for SYMLINK/READLINK"
11319 + "/REALPATH packet", 0);
11323 + _libssh2_debug(session, LIBSSH2_DBG_SFTP, "%s %s on %s",
11325 + LIBSSH2_SFTP_SYMLINK) ? "Creating" : "Reading",
11327 + LIBSSH2_SFTP_REALPATH) ? "realpath" : "symlink", path);
11329 + libssh2_htonu32(s, packet_len - 4);
11331 + switch (link_type) {
11332 + case LIBSSH2_SFTP_REALPATH:
11333 + *(s++) = SSH_FXP_REALPATH;
11336 + case LIBSSH2_SFTP_SYMLINK:
11337 + *(s++) = SSH_FXP_SYMLINK;
11340 + case LIBSSH2_SFTP_READLINK:
11342 + *(s++) = SSH_FXP_READLINK;
11344 + sftp->symlink_request_id = sftp->request_id++;
11345 + libssh2_htonu32(s, sftp->symlink_request_id);
11347 + libssh2_htonu32(s, path_len);
11349 + memcpy(s, path, path_len);
11351 + if (link_type == LIBSSH2_SFTP_SYMLINK) {
11352 + libssh2_htonu32(s, target_len);
11354 + memcpy(s, target, target_len);
11358 + sftp->symlink_state = libssh2_NB_state_created;
11361 + if (sftp->symlink_state == libssh2_NB_state_created) {
11362 + rc = libssh2_channel_write_ex(channel, 0,
11363 + (char *) sftp->symlink_packet,
11365 + if (rc == PACKET_EAGAIN) {
11366 + return PACKET_EAGAIN;
11367 + } else if (packet_len != rc) {
11368 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
11369 + "Unable to send SYMLINK/READLINK command", 0);
11370 + LIBSSH2_FREE(session, sftp->symlink_packet);
11371 + sftp->symlink_packet = NULL;
11372 + sftp->symlink_state = libssh2_NB_state_idle;
11375 + LIBSSH2_FREE(session, sftp->symlink_packet);
11376 + sftp->symlink_packet = NULL;
11378 + sftp->symlink_state = libssh2_NB_state_sent;
11381 + rc = sftp_packet_requirev(sftp, 2, link_responses,
11382 + sftp->symlink_request_id, &data,
11384 + if (rc == PACKET_EAGAIN) {
11385 + return PACKET_EAGAIN;
11388 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
11389 + "Timeout waiting for status message", 0);
11390 + sftp->symlink_state = libssh2_NB_state_idle;
11394 + sftp->symlink_state = libssh2_NB_state_idle;
11396 + if (data[0] == SSH_FXP_STATUS) {
11399 + retcode = libssh2_ntohu32(data + 5);
11400 + LIBSSH2_FREE(session, data);
11401 + if (retcode == LIBSSH2_FX_OK) {
11404 + sftp->last_errno = retcode;
11405 + libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
11406 + "SFTP Protocol Error", 0);
11411 + if (libssh2_ntohu32(data + 5) < 1) {
11412 + libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
11413 + "Invalid READLINK/REALPATH response, no name entries",
11415 + LIBSSH2_FREE(session, data);
11419 + link_len = libssh2_ntohu32(data + 9);
11420 + if (link_len >= target_len) {
11421 + link_len = target_len - 1;
11423 + memcpy(target, data + 13, link_len);
11424 + target[link_len] = 0;
11425 + LIBSSH2_FREE(session, data);
11432 +/* {{{ libssh2_sftp_last_error
11433 + * Returns the last error code reported by SFTP
11435 +LIBSSH2_API unsigned long
11436 +libssh2_sftp_last_error(LIBSSH2_SFTP * sftp)
11438 + return sftp->last_errno;
11443 Property changes on: libssh2/src/sftp.c
11444 ___________________________________________________________________
11445 Added: svn:mime-type
11447 Added: svn:keywords
11448 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
11449 Added: cvs2svn:cvs-rev
11451 Added: svn:eol-style
11454 Index: libssh2/src/libssh2_config.h.in.w32
11455 ===================================================================
11456 --- libssh2/src/libssh2_config.h.in.w32 (.../tags/RELEASE_0_11_0)
11457 +++ libssh2/src/libssh2_config.h.in.w32 (.../trunk)
11459 +#ifndef LIBSSH2_CONFIG_H
11460 +#define LIBSSH2_CONFIG_H
11465 +#include <winsock2.h>
11466 +#include <mswsock.h>
11467 +#include <ws2tcpip.h>
11469 +#ifdef __MINGW32__
11470 +#define HAVE_UNISTD_H
11471 +#define HAVE_INTTYPES_H
11472 +#define HAVE_SYS_TIME_H
11475 +#define HAVE_WINSOCK2_H
11476 +#define HAVE_IOCTLSOCKET
11477 +#define HAVE_SELECT
11480 +#define snprintf _snprintf
11481 +#if _MSC_VER < 1500
11482 +#define vsnprintf _vsnprintf
11484 +#define ssize_t SSIZE_T
11485 +#define uint32_t UINT32
11487 +#define strncasecmp _strnicmp
11488 +#define strcasecmp _stricmp
11490 +#define strncasecmp strnicmp
11491 +#define strcasecmp stricmp
11492 +#endif /* _MSC_VER */
11494 +/* Compile in zlib support */
11495 +#define LIBSSH2_HAVE_ZLIB 1
11497 +/* Enable newer diffie-hellman-group-exchange-sha1 syntax */
11498 +#define LIBSSH2_DH_GEX_NEW 1
11500 +#endif /* LIBSSH2_CONFIG_H */
11504 Property changes on: libssh2/src/libssh2_config.h.in.w32
11505 ___________________________________________________________________
11506 Added: svn:keywords
11507 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
11508 Added: cvs2svn:cvs-rev
11510 Added: svn:eol-style
11512 Added: svn:executable
11515 Index: libssh2/src/pem.c
11516 ===================================================================
11517 --- libssh2/src/pem.c (.../tags/RELEASE_0_11_0)
11518 +++ libssh2/src/pem.c (.../trunk)
11520 +/* Copyright (C) 2007 The Written Word, Inc.
11521 + * Copyright (C) 2008, Simon Josefsson
11522 + * All rights reserved.
11524 + * Redistribution and use in source and binary forms,
11525 + * with or without modification, are permitted provided
11526 + * that the following conditions are met:
11528 + * Redistributions of source code must retain the above
11529 + * copyright notice, this list of conditions and the
11530 + * following disclaimer.
11532 + * Redistributions in binary form must reproduce the above
11533 + * copyright notice, this list of conditions and the following
11534 + * disclaimer in the documentation and/or other materials
11535 + * provided with the distribution.
11537 + * Neither the name of the copyright holder nor the names
11538 + * of any other contributors may be used to endorse or
11539 + * promote products derived from this software without
11540 + * specific prior written permission.
11542 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
11543 + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
11544 + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
11545 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
11546 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
11547 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
11548 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
11549 + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
11550 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
11551 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
11552 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
11553 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
11554 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
11555 + * OF SUCH DAMAGE.
11558 +#include "libssh2_priv.h"
11561 +readline(char *line, int line_size, FILE * fp)
11563 + if (!fgets(line, line_size, fp)) {
11566 + if (*line && line[strlen(line) - 1] == '\n') {
11567 + line[strlen(line) - 1] = '\0';
11569 + if (*line && line[strlen(line) - 1] == '\r') {
11570 + line[strlen(line) - 1] = '\0';
11575 +#define LINE_SIZE 128
11578 +_libssh2_pem_parse(LIBSSH2_SESSION * session,
11579 + const char *headerbegin,
11580 + const char *headerend,
11581 + FILE * fp, unsigned char **data, unsigned int *datalen)
11583 + char line[LINE_SIZE];
11584 + char *b64data = NULL;
11585 + unsigned int b64datalen = 0;
11589 + if (readline(line, LINE_SIZE, fp)) {
11593 + while (strcmp(line, headerbegin) != 0);
11602 + linelen = strlen(line);
11603 + tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen);
11608 + memcpy(tmp + b64datalen, line, linelen);
11610 + b64datalen += linelen;
11613 + if (readline(line, LINE_SIZE, fp)) {
11617 + } while (strcmp(line, headerend) != 0);
11619 + if (libssh2_base64_decode(session, (char**) data, datalen,
11620 + b64data, b64datalen)) {
11628 + LIBSSH2_FREE(session, b64data);
11634 +read_asn1_length(const unsigned char *data,
11635 + unsigned int datalen, unsigned int *len)
11637 + unsigned int lenlen;
11640 + if (datalen < 1) {
11645 + if (*len >= 0x80) {
11646 + lenlen = *len & 0x7F;
11648 + if (1 + lenlen > datalen) {
11651 + if (lenlen > 1) {
11659 + nextpos = 1 + lenlen;
11660 + if (lenlen > 2 || 1 + lenlen + *len > datalen) {
11668 +_libssh2_pem_decode_sequence(unsigned char **data, unsigned int *datalen)
11670 + unsigned int len;
11673 + if (*datalen < 1) {
11677 + if ((*data)[0] != '\x30') {
11684 + lenlen = read_asn1_length(*data, *datalen, &len);
11685 + if (lenlen < 0 || lenlen + len != *datalen) {
11690 + *datalen -= lenlen;
11696 +_libssh2_pem_decode_integer(unsigned char **data, unsigned int *datalen,
11697 + unsigned char **i, unsigned int *ilen)
11699 + unsigned int len;
11702 + if (*datalen < 1) {
11706 + if ((*data)[0] != '\x02') {
11713 + lenlen = read_asn1_length(*data, *datalen, &len);
11714 + if (lenlen < 0 || lenlen + len > *datalen) {
11719 + *datalen -= lenlen;
11730 Property changes on: libssh2/src/pem.c
11731 ___________________________________________________________________
11732 Added: svn:mime-type
11734 Added: svn:keywords
11735 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
11736 Added: cvs2svn:cvs-rev
11738 Added: svn:eol-style
11740 Added: svn:executable
11743 Index: libssh2/src/session.c
11744 ===================================================================
11745 --- libssh2/src/session.c (.../tags/RELEASE_0_11_0)
11746 +++ libssh2/src/session.c (.../trunk)
11748 +/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
11749 + * All rights reserved.
11751 + * Redistribution and use in source and binary forms,
11752 + * with or without modification, are permitted provided
11753 + * that the following conditions are met:
11755 + * Redistributions of source code must retain the above
11756 + * copyright notice, this list of conditions and the
11757 + * following disclaimer.
11759 + * Redistributions in binary form must reproduce the above
11760 + * copyright notice, this list of conditions and the following
11761 + * disclaimer in the documentation and/or other materials
11762 + * provided with the distribution.
11764 + * Neither the name of the copyright holder nor the names
11765 + * of any other contributors may be used to endorse or
11766 + * promote products derived from this software without
11767 + * specific prior written permission.
11769 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
11770 + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
11771 + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
11772 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
11773 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
11774 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
11775 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
11776 + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
11777 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
11778 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
11779 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
11780 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
11781 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
11782 + * OF SUCH DAMAGE.
11785 +#include "libssh2_priv.h"
11786 +#include <errno.h>
11787 +#ifdef HAVE_UNISTD_H
11788 +#include <unistd.h>
11790 +#include <stdlib.h>
11791 +#include <fcntl.h>
11793 +#ifdef HAVE_GETTIMEOFDAY
11794 +#include <sys/time.h>
11796 +#ifdef HAVE_ALLOCA_H
11797 +#include <alloca.h>
11800 +/* {{{ libssh2_default_alloc
11803 +LIBSSH2_ALLOC_FUNC(libssh2_default_alloc)
11806 + return malloc(count);
11811 +/* {{{ libssh2_default_free
11814 +LIBSSH2_FREE_FUNC(libssh2_default_free)
11822 +/* {{{ libssh2_default_realloc
11825 +LIBSSH2_REALLOC_FUNC(libssh2_default_realloc)
11828 + return realloc(ptr, count);
11833 +/* {{{ libssh2_banner_receive
11834 + * Wait for a hello from the remote host
11835 + * Allocate a buffer and store the banner in session->remote.banner
11836 + * Returns: 0 on success, PACKET_EAGAIN if read would block, 1 on failure
11839 +libssh2_banner_receive(LIBSSH2_SESSION * session)
11844 + if (session->banner_TxRx_state == libssh2_NB_state_idle) {
11847 + session->banner_TxRx_state = libssh2_NB_state_created;
11849 + banner_len = session->banner_TxRx_total_send;
11852 + while ((banner_len < (int) sizeof(session->banner_TxRx_banner)) &&
11853 + ((banner_len == 0)
11854 + || (session->banner_TxRx_banner[banner_len - 1] != '\n'))) {
11858 + recv(session->socket_fd, &c, 1,
11859 + LIBSSH2_SOCKET_RECV_FLAGS(session));
11863 + switch (WSAGetLastError()) {
11864 + case WSAEWOULDBLOCK:
11868 + case WSAENOTSOCK:
11872 + case WSAENOTCONN:
11873 + case WSAECONNABORTED:
11874 + errno = WSAENOTCONN;
11881 +#endif /* WIN32 */
11882 + if (errno == EAGAIN) {
11883 + session->socket_block_directions =
11884 + LIBSSH2_SESSION_BLOCK_INBOUND;
11885 + session->banner_TxRx_total_send = banner_len;
11886 + return PACKET_EAGAIN;
11889 + /* Some kinda error */
11890 + session->banner_TxRx_state = libssh2_NB_state_idle;
11891 + session->banner_TxRx_total_send = 0;
11896 + session->socket_state = LIBSSH2_SOCKET_DISCONNECTED;
11897 + return PACKET_FAIL;
11901 + /* NULLs are not allowed in SSH banners */
11902 + session->banner_TxRx_state = libssh2_NB_state_idle;
11903 + session->banner_TxRx_total_send = 0;
11907 + session->banner_TxRx_banner[banner_len++] = c;
11910 + while (banner_len &&
11911 + ((session->banner_TxRx_banner[banner_len - 1] == '\n') ||
11912 + (session->banner_TxRx_banner[banner_len - 1] == '\r'))) {
11916 + /* From this point on, we are done here */
11917 + session->banner_TxRx_state = libssh2_NB_state_idle;
11918 + session->banner_TxRx_total_send = 0;
11923 + session->remote.banner = LIBSSH2_ALLOC(session, banner_len + 1);
11924 + if (!session->remote.banner) {
11925 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
11926 + "Error allocating space for remote banner", 0);
11929 + memcpy(session->remote.banner, session->banner_TxRx_banner, banner_len);
11930 + session->remote.banner[banner_len] = '\0';
11931 + _libssh2_debug(session, LIBSSH2_DBG_TRANS, "Received Banner: %s",
11932 + session->remote.banner);
11938 +/* {{{ libssh2_banner_send
11939 + * Send the default banner, or the one set via libssh2_setopt_string
11941 + * Returns PACKET_EAGAIN if it would block - and if it does so, you should
11942 + * call this function again as soon as it is likely that more data can be
11943 + * sent, and this function should then be called with the same argument set
11944 + * (same data pointer and same data_len) until zero or failure is returned.
11947 +libssh2_banner_send(LIBSSH2_SESSION * session)
11949 + char *banner = (char *) LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF;
11950 + int banner_len = sizeof(LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF) - 1;
11952 +#ifdef LIBSSH2DEBUG
11953 + char banner_dup[256];
11956 + if (session->banner_TxRx_state == libssh2_NB_state_idle) {
11957 + if (session->local.banner) {
11958 + /* setopt_string will have given us our \r\n characters */
11959 + banner_len = strlen((char *) session->local.banner);
11960 + banner = (char *) session->local.banner;
11962 +#ifdef LIBSSH2DEBUG
11963 + /* Hack and slash to avoid sending CRLF in debug output */
11964 + if (banner_len < 256) {
11965 + memcpy(banner_dup, banner, banner_len - 2);
11966 + banner_dup[banner_len - 2] = '\0';
11968 + memcpy(banner_dup, banner, 255);
11969 + banner[255] = '\0';
11972 + _libssh2_debug(session, LIBSSH2_DBG_TRANS, "Sending Banner: %s",
11976 + session->banner_TxRx_state = libssh2_NB_state_created;
11980 + send(session->socket_fd, banner + session->banner_TxRx_total_send,
11981 + banner_len - session->banner_TxRx_total_send,
11982 + LIBSSH2_SOCKET_SEND_FLAGS(session));
11984 + if (ret != (banner_len - session->banner_TxRx_total_send)) {
11985 + if ((ret > 0) || ((ret == -1) && (errno == EAGAIN))) {
11986 + /* the whole packet could not be sent, save the what was */
11987 + session->socket_block_directions =
11988 + LIBSSH2_SESSION_BLOCK_OUTBOUND;
11989 + session->banner_TxRx_total_send += ret;
11990 + return PACKET_EAGAIN;
11992 + session->banner_TxRx_state = libssh2_NB_state_idle;
11993 + session->banner_TxRx_total_send = 0;
11994 + return PACKET_FAIL;
11997 + /* Set the state back to idle */
11998 + session->banner_TxRx_state = libssh2_NB_state_idle;
11999 + session->banner_TxRx_total_send = 0;
12007 + * _libssh2_nonblock() sets the given socket to either blocking or
12008 + * non-blocking mode based on the 'nonblock' boolean argument. This function
12009 + * is copied from the libcurl sources with permission.
12012 +_libssh2_nonblock(int sockfd, /* operate on this */
12013 + int nonblock /* TRUE or FALSE */ )
12016 +#define SETBLOCK 0
12017 +#ifdef HAVE_O_NONBLOCK
12018 + /* most recent unix versions */
12021 + flags = fcntl(sockfd, F_GETFL, 0);
12023 + return fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
12025 + return fcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK));
12027 +#define SETBLOCK 1
12030 +#if defined(HAVE_FIONBIO) && (SETBLOCK == 0)
12031 + /* older unix versions */
12034 + flags = nonblock;
12035 + return ioctl(sockfd, FIONBIO, &flags);
12037 +#define SETBLOCK 2
12040 +#if defined(HAVE_IOCTLSOCKET) && (SETBLOCK == 0)
12042 + unsigned long flags;
12043 + flags = nonblock;
12045 + return ioctlsocket(sockfd, FIONBIO, &flags);
12047 +#define SETBLOCK 3
12050 +#if defined(HAVE_IOCTLSOCKET_CASE) && (SETBLOCK == 0)
12051 + /* presumably for Amiga */
12052 + return IoctlSocket(sockfd, FIONBIO, (long) nonblock);
12054 +#define SETBLOCK 4
12057 +#if defined(HAVE_SO_NONBLOCK) && (SETBLOCK == 0)
12059 + long b = nonblock ? 1 : 0;
12060 + return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b));
12062 +#define SETBLOCK 5
12065 +#ifdef HAVE_DISABLED_NONBLOCKING
12066 + return 0; /* returns success */
12068 +#define SETBLOCK 6
12071 +#if (SETBLOCK == 0)
12072 +#error "no non-blocking method was found/used/set"
12077 + * _libssh2_get_socket_nonblocking() gets the given blocking or non-blocking
12078 + * state of the socket.
12081 +_libssh2_get_socket_nonblocking(int sockfd)
12082 +{ /* operate on this */
12084 +#define GETBLOCK 0
12085 +#ifdef HAVE_O_NONBLOCK
12086 + /* most recent unix versions */
12089 + if ((flags = fcntl(sockfd, F_GETFL, 0)) == -1) {
12090 + /* Assume blocking on error */
12093 + return (flags & O_NONBLOCK);
12095 +#define GETBLOCK 1
12098 +#if defined(WSAEWOULDBLOCK) && (GETBLOCK == 0)
12100 + unsigned int option_value;
12101 + socklen_t option_len = sizeof(option_value);
12104 + (sockfd, SOL_SOCKET, SO_ERROR, (void *) &option_value, &option_len)) {
12105 + /* Assume blocking on error */
12108 + return (int) option_value;
12110 +#define GETBLOCK 2
12113 +#if defined(HAVE_SO_NONBLOCK) && (GETBLOCK == 0)
12116 + if (getsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b))) {
12117 + /* Assume blocking on error */
12122 +#define GETBLOCK 5
12125 +#ifdef HAVE_DISABLED_NONBLOCKING
12126 + return 1; /* returns blocking */
12128 +#define GETBLOCK 6
12131 +#if (GETBLOCK == 0)
12132 +#error "no non-blocking method was found/used/get"
12136 +/* {{{ libssh2_banner_set
12137 + * Set the local banner
12140 +libssh2_banner_set(LIBSSH2_SESSION * session, const char *banner)
12142 + int banner_len = banner ? strlen(banner) : 0;
12144 + if (session->local.banner) {
12145 + LIBSSH2_FREE(session, session->local.banner);
12146 + session->local.banner = NULL;
12149 + if (!banner_len) {
12153 + session->local.banner = LIBSSH2_ALLOC(session, banner_len + 3);
12154 + if (!session->local.banner) {
12155 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
12156 + "Unable to allocate memory for local banner", 0);
12160 + memcpy(session->local.banner, banner, banner_len);
12161 + session->local.banner[banner_len] = '\0';
12162 + _libssh2_debug(session, LIBSSH2_DBG_TRANS, "Setting local Banner: %s",
12163 + session->local.banner);
12164 + session->local.banner[banner_len++] = '\r';
12165 + session->local.banner[banner_len++] = '\n';
12166 + session->local.banner[banner_len++] = '\0';
12173 +/* {{{ proto libssh2_session_init
12174 + * Allocate and initialize a libssh2 session structure
12175 + * Allows for malloc callbacks in case the calling program has its own memory manager
12176 + * It's allowable (but unadvisable) to define some but not all of the malloc callbacks
12177 + * An additional pointer value may be optionally passed to be sent to the callbacks (so they know who's asking)
12179 +LIBSSH2_API LIBSSH2_SESSION *
12180 +libssh2_session_init_ex(LIBSSH2_ALLOC_FUNC((*my_alloc)),
12181 + LIBSSH2_FREE_FUNC((*my_free)),
12182 + LIBSSH2_REALLOC_FUNC((*my_realloc)), void *abstract)
12184 + LIBSSH2_ALLOC_FUNC((*local_alloc)) = libssh2_default_alloc;
12185 + LIBSSH2_FREE_FUNC((*local_free)) = libssh2_default_free;
12186 + LIBSSH2_REALLOC_FUNC((*local_realloc)) = libssh2_default_realloc;
12187 + LIBSSH2_SESSION *session;
12190 + local_alloc = my_alloc;
12193 + local_free = my_free;
12195 + if (my_realloc) {
12196 + local_realloc = my_realloc;
12199 + session = local_alloc(sizeof(LIBSSH2_SESSION), abstract);
12201 + memset(session, 0, sizeof(LIBSSH2_SESSION));
12202 + session->alloc = local_alloc;
12203 + session->free = local_free;
12204 + session->realloc = local_realloc;
12205 + session->abstract = abstract;
12206 + _libssh2_debug(session, LIBSSH2_DBG_TRANS,
12207 + "New session resource allocated");
12208 + libssh2_crypto_init();
12215 +/* {{{ libssh2_session_callback_set
12216 + * Set (or reset) a callback function
12217 + * Returns the prior address
12219 + * FIXME: this function relies on that we can typecast function pointers
12220 + * to void pointers, which isn't allowed in ISO C!
12222 +LIBSSH2_API void *
12223 +libssh2_session_callback_set(LIBSSH2_SESSION * session,
12224 + int cbtype, void *callback)
12228 + switch (cbtype) {
12229 + case LIBSSH2_CALLBACK_IGNORE:
12230 + oldcb = session->ssh_msg_ignore;
12231 + session->ssh_msg_ignore = callback;
12234 + case LIBSSH2_CALLBACK_DEBUG:
12235 + oldcb = session->ssh_msg_debug;
12236 + session->ssh_msg_debug = callback;
12239 + case LIBSSH2_CALLBACK_DISCONNECT:
12240 + oldcb = session->ssh_msg_disconnect;
12241 + session->ssh_msg_disconnect = callback;
12244 + case LIBSSH2_CALLBACK_MACERROR:
12245 + oldcb = session->macerror;
12246 + session->macerror = callback;
12249 + case LIBSSH2_CALLBACK_X11:
12250 + oldcb = session->x11;
12251 + session->x11 = callback;
12255 + _libssh2_debug(session, LIBSSH2_DBG_TRANS, "Setting Callback %d", cbtype);
12262 +/* {{{ proto libssh2_session_startup
12263 + * session: LIBSSH2_SESSION struct allocated and owned by the calling program
12264 + * Returns: 0 on success, or non-zero on failure
12265 + * Any memory allocated by libssh2 will use alloc/realloc/free
12266 + * callbacks in session
12267 + * socket *must* be populated with an opened and connected socket.
12270 +libssh2_session_startup(LIBSSH2_SESSION * session, int sock)
12274 + if (session->startup_state == libssh2_NB_state_idle) {
12275 + _libssh2_debug(session, LIBSSH2_DBG_TRANS,
12276 + "session_startup for socket %d", sock);
12277 + /* FIXME: on some platforms (like win32) sockets are unsigned */
12279 + /* Did we forget something? */
12280 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_NONE,
12281 + "Bad socket provided", 0);
12282 + return LIBSSH2_ERROR_SOCKET_NONE;
12284 + session->socket_fd = sock;
12286 + session->socket_block =
12287 + !_libssh2_get_socket_nonblocking(session->socket_fd);
12288 + if (session->socket_block) {
12290 + * Since we can't be sure that we are in blocking or there
12291 + * was an error detecting the state, so set to blocking to
12294 + _libssh2_nonblock(session->socket_fd, 0);
12297 + session->startup_state = libssh2_NB_state_created;
12300 + /* TODO: Liveness check */
12302 + if (session->startup_state == libssh2_NB_state_created) {
12303 + rc = libssh2_banner_send(session);
12304 + if (rc == PACKET_EAGAIN) {
12305 + libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
12306 + "Would block sending banner to remote host", 0);
12307 + return LIBSSH2_ERROR_EAGAIN;
12309 + /* Unable to send banner? */
12310 + libssh2_error(session, LIBSSH2_ERROR_BANNER_SEND,
12311 + "Error sending banner to remote host", 0);
12312 + return LIBSSH2_ERROR_BANNER_SEND;
12315 + session->startup_state = libssh2_NB_state_sent;
12318 + if (session->startup_state == libssh2_NB_state_sent) {
12319 + rc = libssh2_banner_receive(session);
12320 + if (rc == PACKET_EAGAIN) {
12321 + libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
12322 + "Would block waiting for banner", 0);
12323 + return LIBSSH2_ERROR_EAGAIN;
12325 + /* Unable to receive banner from remote */
12326 + libssh2_error(session, LIBSSH2_ERROR_BANNER_NONE,
12327 + "Timeout waiting for banner", 0);
12328 + return LIBSSH2_ERROR_BANNER_NONE;
12331 + session->startup_state = libssh2_NB_state_sent1;
12334 + if (session->startup_state == libssh2_NB_state_sent1) {
12335 + rc = libssh2_kex_exchange(session, 0, &session->startup_key_state);
12336 + if (rc == PACKET_EAGAIN) {
12337 + libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
12338 + "Would block exchanging encryption keys", 0);
12339 + return LIBSSH2_ERROR_EAGAIN;
12341 + libssh2_error(session, LIBSSH2_ERROR_KEX_FAILURE,
12342 + "Unable to exchange encryption keys", 0);
12343 + return LIBSSH2_ERROR_KEX_FAILURE;
12346 + session->startup_state = libssh2_NB_state_sent2;
12349 + if (session->startup_state == libssh2_NB_state_sent2) {
12350 + _libssh2_debug(session, LIBSSH2_DBG_TRANS,
12351 + "Requesting userauth service");
12353 + /* Request the userauth service */
12354 + session->startup_service[0] = SSH_MSG_SERVICE_REQUEST;
12355 + libssh2_htonu32(session->startup_service + 1,
12356 + sizeof("ssh-userauth") - 1);
12357 + memcpy(session->startup_service + 5, "ssh-userauth",
12358 + sizeof("ssh-userauth") - 1);
12360 + session->startup_state = libssh2_NB_state_sent3;
12363 + if (session->startup_state == libssh2_NB_state_sent3) {
12364 + rc = libssh2_packet_write(session, session->startup_service,
12365 + sizeof("ssh-userauth") + 5 - 1);
12366 + if (rc == PACKET_EAGAIN) {
12367 + libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
12368 + "Would block asking for ssh-userauth service", 0);
12369 + return LIBSSH2_ERROR_EAGAIN;
12371 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
12372 + "Unable to ask for ssh-userauth service", 0);
12373 + return LIBSSH2_ERROR_SOCKET_SEND;
12376 + session->startup_state = libssh2_NB_state_sent4;
12379 + if (session->startup_state == libssh2_NB_state_sent4) {
12380 + rc = libssh2_packet_require_ex(session, SSH_MSG_SERVICE_ACCEPT,
12381 + &session->startup_data,
12382 + &session->startup_data_len, 0, NULL, 0,
12383 + &session->startup_req_state);
12384 + if (rc == PACKET_EAGAIN) {
12385 + return LIBSSH2_ERROR_EAGAIN;
12387 + return LIBSSH2_ERROR_SOCKET_DISCONNECT;
12389 + session->startup_service_length =
12390 + libssh2_ntohu32(session->startup_data + 1);
12392 + if ((session->startup_service_length != (sizeof("ssh-userauth") - 1))
12393 + || strncmp("ssh-userauth", (char *) session->startup_data + 5,
12394 + session->startup_service_length)) {
12395 + LIBSSH2_FREE(session, session->startup_data);
12396 + session->startup_data = NULL;
12397 + libssh2_error(session, LIBSSH2_ERROR_PROTO,
12398 + "Invalid response received from server", 0);
12399 + return LIBSSH2_ERROR_PROTO;
12401 + LIBSSH2_FREE(session, session->startup_data);
12402 + session->startup_data = NULL;
12404 + session->startup_state = libssh2_NB_state_idle;
12409 + /* just for safety return some error */
12410 + return LIBSSH2_ERROR_INVAL;
12415 +/* {{{ proto libssh2_session_free
12416 + * Frees the memory allocated to the session
12417 + * Also closes and frees any channels attached to this session
12420 +libssh2_session_free(LIBSSH2_SESSION * session)
12424 + if (session->free_state == libssh2_NB_state_idle) {
12425 + _libssh2_debug(session, LIBSSH2_DBG_TRANS, "Freeing session resource",
12426 + session->remote.banner);
12428 + session->state = libssh2_NB_state_created;
12431 + if (session->free_state == libssh2_NB_state_created) {
12432 + while (session->channels.head) {
12433 + LIBSSH2_CHANNEL *tmp = session->channels.head;
12435 + rc = libssh2_channel_free(session->channels.head);
12436 + if (rc == PACKET_EAGAIN) {
12437 + return PACKET_EAGAIN;
12439 + if (tmp == session->channels.head) {
12440 + /* channel_free couldn't do it's job, perform a messy cleanup */
12441 + tmp = session->channels.head;
12444 + session->channels.head = tmp->next;
12447 + LIBSSH2_FREE(session, tmp);
12449 + /* reverse linking isn't important here, we're killing the structure */
12453 + session->state = libssh2_NB_state_sent;
12456 + if (session->state == libssh2_NB_state_sent) {
12457 + while (session->listeners) {
12458 + rc = libssh2_channel_forward_cancel(session->listeners);
12459 + if (rc == PACKET_EAGAIN) {
12460 + return PACKET_EAGAIN;
12464 + session->state = libssh2_NB_state_sent1;
12467 + if (session->state & LIBSSH2_STATE_NEWKEYS) {
12469 + if (session->hostkey && session->hostkey->dtor) {
12470 + session->hostkey->dtor(session, &session->server_hostkey_abstract);
12473 + /* Client to Server */
12475 + if (session->local.crypt && session->local.crypt->dtor) {
12476 + session->local.crypt->dtor(session,
12477 + &session->local.crypt_abstract);
12480 + if (session->local.comp && session->local.comp->dtor) {
12481 + session->local.comp->dtor(session, 1,
12482 + &session->local.comp_abstract);
12485 + if (session->local.mac && session->local.mac->dtor) {
12486 + session->local.mac->dtor(session, &session->local.mac_abstract);
12489 + /* Server to Client */
12491 + if (session->remote.crypt && session->remote.crypt->dtor) {
12492 + session->remote.crypt->dtor(session,
12493 + &session->remote.crypt_abstract);
12496 + if (session->remote.comp && session->remote.comp->dtor) {
12497 + session->remote.comp->dtor(session, 0,
12498 + &session->remote.comp_abstract);
12501 + if (session->remote.mac && session->remote.mac->dtor) {
12502 + session->remote.mac->dtor(session, &session->remote.mac_abstract);
12506 + if (session->session_id) {
12507 + LIBSSH2_FREE(session, session->session_id);
12511 + /* Free banner(s) */
12512 + if (session->remote.banner) {
12513 + LIBSSH2_FREE(session, session->remote.banner);
12515 + if (session->local.banner) {
12516 + LIBSSH2_FREE(session, session->local.banner);
12519 + /* Free preference(s) */
12520 + if (session->kex_prefs) {
12521 + LIBSSH2_FREE(session, session->kex_prefs);
12523 + if (session->hostkey_prefs) {
12524 + LIBSSH2_FREE(session, session->hostkey_prefs);
12527 + if (session->local.crypt_prefs) {
12528 + LIBSSH2_FREE(session, session->local.crypt_prefs);
12530 + if (session->local.mac_prefs) {
12531 + LIBSSH2_FREE(session, session->local.mac_prefs);
12533 + if (session->local.comp_prefs) {
12534 + LIBSSH2_FREE(session, session->local.comp_prefs);
12536 + if (session->local.lang_prefs) {
12537 + LIBSSH2_FREE(session, session->local.lang_prefs);
12540 + if (session->remote.crypt_prefs) {
12541 + LIBSSH2_FREE(session, session->remote.crypt_prefs);
12543 + if (session->remote.mac_prefs) {
12544 + LIBSSH2_FREE(session, session->remote.mac_prefs);
12546 + if (session->remote.comp_prefs) {
12547 + LIBSSH2_FREE(session, session->remote.comp_prefs);
12549 + if (session->remote.lang_prefs) {
12550 + LIBSSH2_FREE(session, session->remote.lang_prefs);
12554 + * Make sure all memory used in the state variables are free
12556 + if (session->startup_data) {
12557 + LIBSSH2_FREE(session, session->startup_data);
12559 + if (session->disconnect_data) {
12560 + LIBSSH2_FREE(session, session->disconnect_data);
12562 + if (session->userauth_list_data) {
12563 + LIBSSH2_FREE(session, session->userauth_list_data);
12565 + if (session->userauth_pswd_data) {
12566 + LIBSSH2_FREE(session, session->userauth_pswd_data);
12568 + if (session->userauth_pswd_newpw) {
12569 + LIBSSH2_FREE(session, session->userauth_pswd_newpw);
12571 + if (session->userauth_host_packet) {
12572 + LIBSSH2_FREE(session, session->userauth_host_packet);
12574 + if (session->userauth_host_method) {
12575 + LIBSSH2_FREE(session, session->userauth_host_method);
12577 + if (session->userauth_host_data) {
12578 + LIBSSH2_FREE(session, session->userauth_host_data);
12580 + if (session->userauth_pblc_data) {
12581 + LIBSSH2_FREE(session, session->userauth_pblc_data);
12583 + if (session->userauth_pblc_packet) {
12584 + LIBSSH2_FREE(session, session->userauth_pblc_packet);
12586 + if (session->userauth_pblc_method) {
12587 + LIBSSH2_FREE(session, session->userauth_pblc_method);
12589 + if (session->userauth_kybd_data) {
12590 + LIBSSH2_FREE(session, session->userauth_kybd_data);
12592 + if (session->userauth_kybd_packet) {
12593 + LIBSSH2_FREE(session, session->userauth_kybd_packet);
12595 + if (session->userauth_kybd_auth_instruction) {
12596 + LIBSSH2_FREE(session, session->userauth_kybd_auth_instruction);
12598 + if (session->open_packet) {
12599 + LIBSSH2_FREE(session, session->open_packet);
12601 + if (session->open_data) {
12602 + LIBSSH2_FREE(session, session->open_data);
12604 + if (session->direct_message) {
12605 + LIBSSH2_FREE(session, session->direct_message);
12607 + if (session->fwdLstn_packet) {
12608 + LIBSSH2_FREE(session, session->fwdLstn_packet);
12610 + if (session->pkeyInit_data) {
12611 + LIBSSH2_FREE(session, session->pkeyInit_data);
12613 + if (session->scpRecv_command) {
12614 + LIBSSH2_FREE(session, session->scpRecv_command);
12616 + if (session->scpSend_command) {
12617 + LIBSSH2_FREE(session, session->scpSend_command);
12619 + if (session->scpRecv_err_msg) {
12620 + LIBSSH2_FREE(session, session->scpRecv_err_msg);
12622 + if (session->scpSend_err_msg) {
12623 + LIBSSH2_FREE(session, session->scpSend_err_msg);
12626 + /* Free the error message, if we ar supposed to */
12627 + if (session->err_msg && session->err_should_free) {
12628 + LIBSSH2_FREE(session, session->err_msg);
12631 + /* Cleanup any remaining packets */
12632 + while (session->packets.head) {
12633 + LIBSSH2_PACKET *tmp = session->packets.head;
12636 + session->packets.head = tmp->next;
12639 + LIBSSH2_FREE(session, tmp->data);
12640 + LIBSSH2_FREE(session, tmp);
12643 + LIBSSH2_FREE(session, session);
12650 +/* {{{ libssh2_session_disconnect_ex
12653 +libssh2_session_disconnect_ex(LIBSSH2_SESSION * session, int reason,
12654 + const char *description, const char *lang)
12656 + unsigned char *s;
12657 + unsigned long descr_len = 0, lang_len = 0;
12660 + if (session->disconnect_state == libssh2_NB_state_idle) {
12661 + _libssh2_debug(session, LIBSSH2_DBG_TRANS,
12662 + "Disconnecting: reason=%d, desc=%s, lang=%s", reason,
12663 + description, lang);
12664 + if (description) {
12665 + descr_len = strlen(description);
12668 + lang_len = strlen(lang);
12670 + /* 13 = packet_type(1) + reason code(4) + descr_len(4) + lang_len(4) */
12671 + session->disconnect_data_len = descr_len + lang_len + 13;
12673 + s = session->disconnect_data =
12674 + LIBSSH2_ALLOC(session, session->disconnect_data_len);
12675 + if (!session->disconnect_data) {
12676 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
12677 + "Unable to allocate memory for disconnect packet",
12679 + session->disconnect_state = libssh2_NB_state_idle;
12683 + *(s++) = SSH_MSG_DISCONNECT;
12684 + libssh2_htonu32(s, reason);
12687 + libssh2_htonu32(s, descr_len);
12689 + if (description) {
12690 + memcpy(s, description, descr_len);
12694 + libssh2_htonu32(s, lang_len);
12697 + memcpy(s, lang, lang_len);
12701 + session->disconnect_state = libssh2_NB_state_created;
12704 + rc = libssh2_packet_write(session, session->disconnect_data,
12705 + session->disconnect_data_len);
12706 + if (rc == PACKET_EAGAIN) {
12707 + return PACKET_EAGAIN;
12710 + LIBSSH2_FREE(session, session->disconnect_data);
12711 + session->disconnect_data = NULL;
12712 + session->disconnect_state = libssh2_NB_state_idle;
12719 +/* {{{ libssh2_session_methods
12720 + * Return the currently active methods for method_type
12721 + * NOTE: Currently lang_cs and lang_sc are ALWAYS set to empty string regardless of actual negotiation
12722 + * Strings should NOT be freed
12724 +LIBSSH2_API const char *
12725 +libssh2_session_methods(LIBSSH2_SESSION * session, int method_type)
12727 + /* All methods have char *name as their first element */
12728 + const LIBSSH2_KEX_METHOD *method = NULL;
12730 + switch (method_type) {
12731 + case LIBSSH2_METHOD_KEX:
12732 + method = session->kex;
12735 + case LIBSSH2_METHOD_HOSTKEY:
12736 + method = (LIBSSH2_KEX_METHOD *) session->hostkey;
12739 + case LIBSSH2_METHOD_CRYPT_CS:
12740 + method = (LIBSSH2_KEX_METHOD *) session->local.crypt;
12743 + case LIBSSH2_METHOD_CRYPT_SC:
12744 + method = (LIBSSH2_KEX_METHOD *) session->remote.crypt;
12747 + case LIBSSH2_METHOD_MAC_CS:
12748 + method = (LIBSSH2_KEX_METHOD *) session->local.mac;
12751 + case LIBSSH2_METHOD_MAC_SC:
12752 + method = (LIBSSH2_KEX_METHOD *) session->remote.mac;
12755 + case LIBSSH2_METHOD_COMP_CS:
12756 + method = (LIBSSH2_KEX_METHOD *) session->local.comp;
12759 + case LIBSSH2_METHOD_COMP_SC:
12760 + method = (LIBSSH2_KEX_METHOD *) session->remote.comp;
12763 + case LIBSSH2_METHOD_LANG_CS:
12767 + case LIBSSH2_METHOD_LANG_SC:
12772 + libssh2_error(session, LIBSSH2_ERROR_INVAL,
12773 + "Invalid parameter specified for method_type", 0);
12779 + libssh2_error(session, LIBSSH2_ERROR_METHOD_NONE,
12780 + "No method negotiated", 0);
12784 + return method->name;
12789 +/* {{{ libssh2_session_abstract
12790 + * Retrieve a pointer to the abstract property
12792 +LIBSSH2_API void **
12793 +libssh2_session_abstract(LIBSSH2_SESSION * session)
12795 + return &session->abstract;
12800 +/* {{{ libssh2_session_last_error
12801 + * Returns error code and populates an error string into errmsg
12802 + * If want_buf is non-zero then the string placed into errmsg must be freed by the calling program
12803 + * Otherwise it is assumed to be owned by libssh2
12806 +libssh2_session_last_error(LIBSSH2_SESSION * session, char **errmsg,
12807 + int *errmsg_len, int want_buf)
12809 + /* No error to report */
12810 + if (!session->err_code) {
12813 + *errmsg = LIBSSH2_ALLOC(session, 1);
12818 + *errmsg = (char *) "";
12821 + if (errmsg_len) {
12828 + char *serrmsg = session->err_msg ? session->err_msg : (char *) "";
12829 + int ownbuf = session->err_msg ? session->err_should_free : 0;
12833 + /* Just give the calling program the buffer */
12834 + *errmsg = serrmsg;
12835 + session->err_should_free = 0;
12837 + /* Make a copy so the calling program can own it */
12838 + *errmsg = LIBSSH2_ALLOC(session, session->err_msglen + 1);
12840 + memcpy(*errmsg, session->err_msg, session->err_msglen);
12841 + (*errmsg)[session->err_msglen] = 0;
12845 + *errmsg = serrmsg;
12849 + if (errmsg_len) {
12850 + *errmsg_len = session->err_msglen;
12853 + return session->err_code;
12858 +/* {{{ libssh2_session_last_error
12859 +* Returns error code
12862 +libssh2_session_last_errno(LIBSSH2_SESSION * session)
12864 + return session->err_code;
12869 +/* {{{ libssh2_session_flag
12870 + * Set/Get session flags
12871 + * Passing flag==0 will avoid changing session->flags while still returning its current value
12874 +libssh2_session_flag(LIBSSH2_SESSION * session, int flag, int value)
12877 + session->flags |= flag;
12879 + session->flags &= ~flag;
12882 + return session->flags;
12887 +/* {{{ _libssh2_session_set_blocking
12888 + * Set a session's blocking mode on or off, return the previous status
12889 + * when this function is called.
12892 +_libssh2_session_set_blocking(LIBSSH2_SESSION * session, int blocking)
12894 + int bl = session->socket_block;
12895 + _libssh2_debug(session, LIBSSH2_DBG_CONN,
12896 + "Setting blocking mode on session %d", blocking);
12897 + if (blocking == session->socket_block) {
12898 + /* avoid if already correct */
12901 + session->socket_block = blocking;
12903 + _libssh2_nonblock(session->socket_fd, !blocking);
12910 +/* {{{ libssh2_session_set_blocking
12911 + * Set a channel's blocking mode on or off, similar to a socket's
12912 + * fcntl(fd, F_SETFL, O_NONBLOCK); type command
12915 +libssh2_session_set_blocking(LIBSSH2_SESSION * session, int blocking)
12917 + (void) _libssh2_session_set_blocking(session, blocking);
12922 +/* {{{ libssh2_session_get_blocking
12923 +* Returns a session's blocking mode on or off
12926 +libssh2_session_get_blocking(LIBSSH2_SESSION * session)
12928 + return session->socket_block;
12933 +/* {{{ libssh2_poll_channel_read
12934 + * Returns 0 if no data is waiting on channel,
12935 + * non-0 if data is available
12938 +libssh2_poll_channel_read(LIBSSH2_CHANNEL * channel, int extended)
12940 + LIBSSH2_SESSION *session = channel->session;
12941 + LIBSSH2_PACKET *packet = session->packets.head;
12945 + if ( channel->local.id == libssh2_ntohu32(packet->data + 1)) {
12946 + if ( extended == 1 &&
12947 + (packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA
12948 + || packet->data[0] == SSH_MSG_CHANNEL_DATA )) {
12950 + } else if ( extended == 0 &&
12951 + packet->data[0] == SSH_MSG_CHANNEL_DATA) {
12954 + /* else - no data of any type is ready to be read */
12956 + packet = packet->next;
12964 +/* {{{ libssh2_poll_channel_write
12965 + * Returns 0 if writing to channel would block,
12966 + * non-0 if data can be written without blocking
12969 +libssh2_poll_channel_write(LIBSSH2_CHANNEL * channel)
12971 + return channel->local.window_size ? 1 : 0;
12976 +/* {{{ libssh2_poll_listener_queued
12977 + * Returns 0 if no connections are waiting to be accepted
12978 + * non-0 if one or more connections are available
12981 +libssh2_poll_listener_queued(LIBSSH2_LISTENER * listener)
12983 + return listener->queue ? 1 : 0;
12988 +/* {{{ libssh2_poll
12989 + * Poll sockets, channels, and listeners for activity
12992 +libssh2_poll(LIBSSH2_POLLFD * fds, unsigned int nfds, long timeout)
12994 + long timeout_remaining;
12995 + unsigned int i, active_fds;
12997 + LIBSSH2_SESSION *session = NULL;
12998 +#ifdef HAVE_ALLOCA
12999 + struct pollfd *sockets = alloca(sizeof(struct pollfd) * nfds);
13001 + struct pollfd sockets[256];
13004 + /* systems without alloca use a fixed-size array, this can be fixed
13005 + if we really want to, at least if the compiler is a C99 capable one */
13008 + /* Setup sockets for polling */
13009 + for(i = 0; i < nfds; i++) {
13010 + fds[i].revents = 0;
13011 + switch (fds[i].type) {
13012 + case LIBSSH2_POLLFD_SOCKET:
13013 + sockets[i].fd = fds[i].fd.socket;
13014 + sockets[i].events = fds[i].events;
13015 + sockets[i].revents = 0;
13018 + case LIBSSH2_POLLFD_CHANNEL:
13019 + sockets[i].fd = fds[i].fd.channel->session->socket_fd;
13020 + sockets[i].events = POLLIN;
13021 + sockets[i].revents = 0;
13023 + session = fds[i].fd.channel->session;
13026 + case LIBSSH2_POLLFD_LISTENER:
13027 + sockets[i].fd = fds[i].fd.listener->session->socket_fd;
13028 + sockets[i].events = POLLIN;
13029 + sockets[i].revents = 0;
13031 + session = fds[i].fd.listener->session;
13036 + libssh2_error(session, LIBSSH2_ERROR_INVALID_POLL_TYPE,
13037 + "Invalid descriptor passed to libssh2_poll()",
13042 +#elif defined(HAVE_SELECT)
13043 + LIBSSH2_SESSION *session = NULL;
13045 + fd_set rfds, wfds;
13046 + struct timeval tv;
13050 + for(i = 0; i < nfds; i++) {
13051 + fds[i].revents = 0;
13052 + switch (fds[i].type) {
13053 + case LIBSSH2_POLLFD_SOCKET:
13054 + if (fds[i].events & LIBSSH2_POLLFD_POLLIN) {
13055 + FD_SET(fds[i].fd.socket, &rfds);
13056 + if (fds[i].fd.socket > maxfd)
13057 + maxfd = fds[i].fd.socket;
13059 + if (fds[i].events & LIBSSH2_POLLFD_POLLOUT) {
13060 + FD_SET(fds[i].fd.socket, &wfds);
13061 + if (fds[i].fd.socket > maxfd)
13062 + maxfd = fds[i].fd.socket;
13066 + case LIBSSH2_POLLFD_CHANNEL:
13067 + FD_SET(fds[i].fd.channel->session->socket_fd, &rfds);
13068 + if (fds[i].fd.channel->session->socket_fd > maxfd)
13069 + maxfd = fds[i].fd.channel->session->socket_fd;
13071 + session = fds[i].fd.channel->session;
13074 + case LIBSSH2_POLLFD_LISTENER:
13075 + FD_SET(fds[i].fd.listener->session->socket_fd, &rfds);
13076 + if (fds[i].fd.listener->session->socket_fd > maxfd)
13077 + maxfd = fds[i].fd.listener->session->socket_fd;
13079 + session = fds[i].fd.listener->session;
13084 + libssh2_error(session, LIBSSH2_ERROR_INVALID_POLL_TYPE,
13085 + "Invalid descriptor passed to libssh2_poll()",
13091 + /* No select() or poll()
13092 + * no sockets sturcture to setup
13096 +#endif /* HAVE_POLL or HAVE_SELECT */
13098 + timeout_remaining = timeout;
13100 +#if defined(HAVE_POLL) || defined(HAVE_SELECT)
13106 + for(i = 0; i < nfds; i++) {
13107 + if (fds[i].events != fds[i].revents) {
13108 + switch (fds[i].type) {
13109 + case LIBSSH2_POLLFD_CHANNEL:
13110 + if ((fds[i].events & LIBSSH2_POLLFD_POLLIN) && /* Want to be ready for read */
13111 + ((fds[i].revents & LIBSSH2_POLLFD_POLLIN) == 0)) { /* Not yet known to be ready for read */
13112 + fds[i].revents |=
13113 + libssh2_poll_channel_read(fds[i].fd.channel,
13115 + LIBSSH2_POLLFD_POLLIN : 0;
13117 + if ((fds[i].events & LIBSSH2_POLLFD_POLLEXT) && /* Want to be ready for extended read */
13118 + ((fds[i].revents & LIBSSH2_POLLFD_POLLEXT) == 0)) { /* Not yet known to be ready for extended read */
13119 + fds[i].revents |=
13120 + libssh2_poll_channel_read(fds[i].fd.channel,
13122 + LIBSSH2_POLLFD_POLLEXT : 0;
13124 + if ((fds[i].events & LIBSSH2_POLLFD_POLLOUT) && /* Want to be ready for write */
13125 + ((fds[i].revents & LIBSSH2_POLLFD_POLLOUT) == 0)) { /* Not yet known to be ready for write */
13126 + fds[i].revents |=
13127 + libssh2_poll_channel_write(fds[i].fd.
13129 + LIBSSH2_POLLFD_POLLOUT : 0;
13131 + if (fds[i].fd.channel->remote.close
13132 + || fds[i].fd.channel->local.close) {
13133 + fds[i].revents |= LIBSSH2_POLLFD_CHANNEL_CLOSED;
13135 + if (fds[i].fd.channel->session->socket_state ==
13136 + LIBSSH2_SOCKET_DISCONNECTED) {
13137 + fds[i].revents |=
13138 + LIBSSH2_POLLFD_CHANNEL_CLOSED |
13139 + LIBSSH2_POLLFD_SESSION_CLOSED;
13143 + case LIBSSH2_POLLFD_LISTENER:
13144 + if ((fds[i].events & LIBSSH2_POLLFD_POLLIN) && /* Want a connection */
13145 + ((fds[i].revents & LIBSSH2_POLLFD_POLLIN) == 0)) { /* No connections known of yet */
13146 + fds[i].revents |=
13147 + libssh2_poll_listener_queued(fds[i].fd.
13149 + LIBSSH2_POLLFD_POLLIN : 0;
13151 + if (fds[i].fd.listener->session->socket_state ==
13152 + LIBSSH2_SOCKET_DISCONNECTED) {
13153 + fds[i].revents |=
13154 + LIBSSH2_POLLFD_LISTENER_CLOSED |
13155 + LIBSSH2_POLLFD_SESSION_CLOSED;
13160 + if (fds[i].revents) {
13165 + if (active_fds) {
13166 + /* Don't block on the sockets if we have channels/listeners which are ready */
13167 + timeout_remaining = 0;
13171 +#ifdef HAVE_GETTIMEOFDAY
13173 + struct timeval tv_begin, tv_end;
13175 + gettimeofday((struct timeval *) &tv_begin, NULL);
13176 + sysret = poll(sockets, nfds, timeout_remaining);
13177 + gettimeofday((struct timeval *) &tv_end, NULL);
13178 + timeout_remaining -= (tv_end.tv_sec - tv_begin.tv_sec) * 1000;
13179 + timeout_remaining -= (tv_end.tv_usec - tv_begin.tv_usec) / 1000;
13182 + /* If the platform doesn't support gettimeofday,
13183 + * then just make the call non-blocking and walk away
13185 + sysret = poll(sockets, nfds, timeout_remaining);
13186 + timeout_remaining = 0;
13187 +#endif /* HAVE_GETTIMEOFDAY */
13189 + if (sysret > 0) {
13190 + for(i = 0; i < nfds; i++) {
13191 + switch (fds[i].type) {
13192 + case LIBSSH2_POLLFD_SOCKET:
13193 + fds[i].revents = sockets[i].revents;
13194 + sockets[i].revents = 0; /* In case we loop again, be nice */
13195 + if (fds[i].revents) {
13199 + case LIBSSH2_POLLFD_CHANNEL:
13200 + if (sockets[i].events & POLLIN) {
13201 + /* Spin session until no data available */
13202 + while (libssh2_packet_read(fds[i].fd.channel->session)
13205 + if (sockets[i].revents & POLLHUP) {
13206 + fds[i].revents |=
13207 + LIBSSH2_POLLFD_CHANNEL_CLOSED |
13208 + LIBSSH2_POLLFD_SESSION_CLOSED;
13210 + sockets[i].revents = 0;
13212 + case LIBSSH2_POLLFD_LISTENER:
13213 + if (sockets[i].events & POLLIN) {
13214 + /* Spin session until no data available */
13215 + while (libssh2_packet_read(fds[i].fd.listener->session)
13218 + if (sockets[i].revents & POLLHUP) {
13219 + fds[i].revents |=
13220 + LIBSSH2_POLLFD_LISTENER_CLOSED |
13221 + LIBSSH2_POLLFD_SESSION_CLOSED;
13223 + sockets[i].revents = 0;
13228 +#elif defined(HAVE_SELECT)
13229 + tv.tv_sec = timeout_remaining / 1000;
13230 + tv.tv_usec = (timeout_remaining % 1000) * 1000;
13231 +#ifdef HAVE_GETTIMEOFDAY
13233 + struct timeval tv_begin, tv_end;
13235 + gettimeofday((struct timeval *) &tv_begin, NULL);
13236 + sysret = select(maxfd+1, &rfds, &wfds, NULL, &tv);
13237 + gettimeofday((struct timeval *) &tv_end, NULL);
13239 + timeout_remaining -= (tv_end.tv_sec - tv_begin.tv_sec) * 1000;
13240 + timeout_remaining -= (tv_end.tv_usec - tv_begin.tv_usec) / 1000;
13243 + /* If the platform doesn't support gettimeofday,
13244 + * then just make the call non-blocking and walk away
13246 + sysret = select(maxfd+1, &rfds, &wfds, NULL, &tv);
13247 + timeout_remaining = 0;
13250 + if (sysret > 0) {
13251 + for(i = 0; i < nfds; i++) {
13252 + switch (fds[i].type) {
13253 + case LIBSSH2_POLLFD_SOCKET:
13254 + if (FD_ISSET(fds[i].fd.socket, &rfds)) {
13255 + fds[i].revents |= LIBSSH2_POLLFD_POLLIN;
13257 + if (FD_ISSET(fds[i].fd.socket, &wfds)) {
13258 + fds[i].revents |= LIBSSH2_POLLFD_POLLOUT;
13260 + if (fds[i].revents) {
13265 + case LIBSSH2_POLLFD_CHANNEL:
13266 + if (FD_ISSET(fds[i].fd.channel->session->socket_fd, &rfds)) {
13267 + /* Spin session until no data available */
13268 + while (libssh2_packet_read(fds[i].fd.channel->session)
13273 + case LIBSSH2_POLLFD_LISTENER:
13275 + (fds[i].fd.listener->session->socket_fd, &rfds)) {
13276 + /* Spin session until no data available */
13277 + while (libssh2_packet_read(fds[i].fd.listener->session)
13284 +#endif /* else no select() or poll() -- timeout (and by extension timeout_remaining) will be equal to 0 */
13285 + } while ((timeout_remaining > 0) && !active_fds);
13287 + return active_fds;
13290 +/* {{{ libssh2_session_block_direction
13291 + * Get blocked direction when a function returns LIBSSH2_ERROR_EAGAIN
13292 + * Returns LIBSSH2_SOCKET_BLOCK_INBOUND if recv() blocked
13293 + * or LIBSSH2_SOCKET_BLOCK_OUTBOUND if send() blocked
13296 +libssh2_session_block_directions(LIBSSH2_SESSION *session)
13298 + return session->socket_block_directions;
13303 Property changes on: libssh2/src/session.c
13304 ___________________________________________________________________
13305 Added: svn:mime-type
13307 Added: svn:keywords
13308 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
13309 Added: cvs2svn:cvs-rev
13311 Added: svn:eol-style
13314 Index: libssh2/src/openssl.c
13315 ===================================================================
13316 --- libssh2/src/openssl.c (.../tags/RELEASE_0_11_0)
13317 +++ libssh2/src/openssl.c (.../trunk)
13319 +/* Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved.
13320 + * Author: Simon Josefsson
13321 + * Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
13323 + * Redistribution and use in source and binary forms,
13324 + * with or without modification, are permitted provided
13325 + * that the following conditions are met:
13327 + * Redistributions of source code must retain the above
13328 + * copyright notice, this list of conditions and the
13329 + * following disclaimer.
13331 + * Redistributions in binary form must reproduce the above
13332 + * copyright notice, this list of conditions and the following
13333 + * disclaimer in the documentation and/or other materials
13334 + * provided with the distribution.
13336 + * Neither the name of the copyright holder nor the names
13337 + * of any other contributors may be used to endorse or
13338 + * promote products derived from this software without
13339 + * specific prior written permission.
13341 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
13342 + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
13343 + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
13344 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13345 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
13346 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
13347 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
13348 + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
13349 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
13350 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
13351 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
13352 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
13353 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
13354 + * OF SUCH DAMAGE.
13357 +#include "libssh2_priv.h"
13358 +#include <string.h>
13360 +#ifndef EVP_MAX_BLOCK_LENGTH
13361 +#define EVP_MAX_BLOCK_LENGTH 32
13365 +_libssh2_rsa_new(libssh2_rsa_ctx ** rsa,
13366 + const unsigned char *edata,
13367 + unsigned long elen,
13368 + const unsigned char *ndata,
13369 + unsigned long nlen,
13370 + const unsigned char *ddata,
13371 + unsigned long dlen,
13372 + const unsigned char *pdata,
13373 + unsigned long plen,
13374 + const unsigned char *qdata,
13375 + unsigned long qlen,
13376 + const unsigned char *e1data,
13377 + unsigned long e1len,
13378 + const unsigned char *e2data,
13379 + unsigned long e2len,
13380 + const unsigned char *coeffdata, unsigned long coefflen)
13382 + *rsa = RSA_new();
13384 + (*rsa)->e = BN_new();
13385 + BN_bin2bn(edata, elen, (*rsa)->e);
13387 + (*rsa)->n = BN_new();
13388 + BN_bin2bn(ndata, nlen, (*rsa)->n);
13391 + (*rsa)->d = BN_new();
13392 + BN_bin2bn(ddata, dlen, (*rsa)->d);
13394 + (*rsa)->p = BN_new();
13395 + BN_bin2bn(pdata, plen, (*rsa)->p);
13397 + (*rsa)->q = BN_new();
13398 + BN_bin2bn(qdata, qlen, (*rsa)->q);
13400 + (*rsa)->dmp1 = BN_new();
13401 + BN_bin2bn(e1data, e1len, (*rsa)->dmp1);
13403 + (*rsa)->dmq1 = BN_new();
13404 + BN_bin2bn(e2data, e2len, (*rsa)->dmq1);
13406 + (*rsa)->iqmp = BN_new();
13407 + BN_bin2bn(coeffdata, coefflen, (*rsa)->iqmp);
13413 +_libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsactx,
13414 + const unsigned char *sig,
13415 + unsigned long sig_len,
13416 + const unsigned char *m, unsigned long m_len)
13418 + unsigned char hash[SHA_DIGEST_LENGTH];
13421 + SHA1(m, m_len, hash);
13422 + ret = RSA_verify(NID_sha1, hash, SHA_DIGEST_LENGTH,
13423 + (unsigned char *) sig, sig_len, rsactx);
13424 + return (ret == 1) ? 0 : -1;
13428 +_libssh2_dsa_new(libssh2_dsa_ctx ** dsactx,
13429 + const unsigned char *p,
13430 + unsigned long p_len,
13431 + const unsigned char *q,
13432 + unsigned long q_len,
13433 + const unsigned char *g,
13434 + unsigned long g_len,
13435 + const unsigned char *y,
13436 + unsigned long y_len,
13437 + const unsigned char *x, unsigned long x_len)
13439 + *dsactx = DSA_new();
13441 + (*dsactx)->p = BN_new();
13442 + BN_bin2bn(p, p_len, (*dsactx)->p);
13444 + (*dsactx)->q = BN_new();
13445 + BN_bin2bn(q, q_len, (*dsactx)->q);
13447 + (*dsactx)->g = BN_new();
13448 + BN_bin2bn(g, g_len, (*dsactx)->g);
13450 + (*dsactx)->pub_key = BN_new();
13451 + BN_bin2bn(y, y_len, (*dsactx)->pub_key);
13454 + (*dsactx)->priv_key = BN_new();
13455 + BN_bin2bn(x, x_len, (*dsactx)->priv_key);
13462 +_libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx,
13463 + const unsigned char *sig,
13464 + const unsigned char *m, unsigned long m_len)
13466 + unsigned char hash[SHA_DIGEST_LENGTH];
13470 + dsasig.r = BN_new();
13471 + BN_bin2bn(sig, 20, dsasig.r);
13472 + dsasig.s = BN_new();
13473 + BN_bin2bn(sig + 20, 20, dsasig.s);
13475 + libssh2_sha1(m, m_len, hash);
13476 + ret = DSA_do_verify(hash, SHA_DIGEST_LENGTH, &dsasig, dsactx);
13477 + BN_clear_free(dsasig.s);
13478 + BN_clear_free(dsasig.r);
13480 + return (ret == 1) ? 0 : -1;
13484 +_libssh2_cipher_init(_libssh2_cipher_ctx * h,
13485 + _libssh2_cipher_type(algo),
13486 + unsigned char *iv, unsigned char *secret, int encrypt)
13488 + EVP_CIPHER_CTX_init(h);
13489 + EVP_CipherInit(h, algo(), secret, iv, encrypt);
13494 +_libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx,
13495 + _libssh2_cipher_type(algo),
13496 + int encrypt, unsigned char *block)
13498 + int blocksize = ctx->cipher->block_size;
13499 + unsigned char buf[EVP_MAX_BLOCK_LENGTH];
13504 + if (blocksize == 1) {
13505 +/* Hack for arcfour. */
13508 + ret = EVP_Cipher(ctx, buf, block, blocksize);
13510 + memcpy(block, buf, blocksize);
13512 + return ret == 1 ? 0 : 1;
13515 +/* TODO: Optionally call a passphrase callback specified by the
13516 + * calling program
13519 +passphrase_cb(char *buf, int size, int rwflag, char *passphrase)
13521 + int passphrase_len = strlen(passphrase);
13524 + if (passphrase_len > (size - 1)) {
13525 + passphrase_len = size - 1;
13527 + memcpy(buf, passphrase, passphrase_len);
13528 + buf[passphrase_len] = '\0';
13530 + return passphrase_len;
13534 +_libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa,
13535 + LIBSSH2_SESSION * session,
13536 + FILE * fp, unsigned const char *passphrase)
13539 + if (!EVP_get_cipherbyname("des")) {
13540 +/* If this cipher isn't loaded it's a pretty good indication that none are.
13541 + * I have *NO DOUBT* that there's a better way to deal with this ($#&%#$(%$#(
13542 + * Someone buy me an OpenSSL manual and I'll read up on it.
13544 + OpenSSL_add_all_ciphers();
13546 + *rsa = PEM_read_RSAPrivateKey(fp, NULL, (void *) passphrase_cb,
13547 + (void *) passphrase);
13555 +_libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa,
13556 + LIBSSH2_SESSION * session,
13557 + FILE * fp, unsigned const char *passphrase)
13560 + if (!EVP_get_cipherbyname("des")) {
13561 +/* If this cipher isn't loaded it's a pretty good indication that none are.
13562 + * I have *NO DOUBT* that there's a better way to deal with this ($#&%#$(%$#(
13563 + * Someone buy me an OpenSSL manual and I'll read up on it.
13565 + OpenSSL_add_all_ciphers();
13567 + *dsa = PEM_read_DSAPrivateKey(fp, NULL, (void *) passphrase_cb,
13568 + (void *) passphrase);
13576 +_libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session,
13577 + libssh2_rsa_ctx * rsactx,
13578 + const unsigned char *hash,
13579 + unsigned long hash_len,
13580 + unsigned char **signature, unsigned long *signature_len)
13583 + unsigned char *sig;
13584 + unsigned int sig_len;
13586 + sig_len = RSA_size(rsactx);
13587 + sig = LIBSSH2_ALLOC(session, sig_len);
13593 + ret = RSA_sign(NID_sha1, hash, hash_len, sig, &sig_len, rsactx);
13596 + LIBSSH2_FREE(session, sig);
13600 + *signature = sig;
13601 + *signature_len = sig_len;
13607 +_libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,
13608 + const unsigned char *hash,
13609 + unsigned long hash_len, unsigned char *signature)
13612 + int r_len, s_len, rs_pad;
13615 + sig = DSA_do_sign(hash, SHA_DIGEST_LENGTH, dsactx);
13620 + r_len = BN_num_bytes(sig->r);
13621 + s_len = BN_num_bytes(sig->s);
13622 + rs_pad = (2 * SHA_DIGEST_LENGTH) - (r_len + s_len);
13623 + if (rs_pad < 0) {
13624 + DSA_SIG_free(sig);
13628 + BN_bn2bin(sig->r, signature + rs_pad);
13629 + BN_bn2bin(sig->s, signature + rs_pad + r_len);
13631 + DSA_SIG_free(sig);
13636 Property changes on: libssh2/src/openssl.c
13637 ___________________________________________________________________
13638 Added: svn:mime-type
13640 Added: svn:keywords
13641 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
13642 Added: cvs2svn:cvs-rev
13644 Added: svn:eol-style
13646 Added: svn:executable
13649 Index: libssh2/src/scp.c
13650 ===================================================================
13651 --- libssh2/src/scp.c (.../tags/RELEASE_0_11_0)
13652 +++ libssh2/src/scp.c (.../trunk)
13654 +/* Copyright (c) 2004-2008, Sara Golemon <sarag@libssh2.org>
13655 + * All rights reserved.
13657 + * Redistribution and use in source and binary forms,
13658 + * with or without modification, are permitted provided
13659 + * that the following conditions are met:
13661 + * Redistributions of source code must retain the above
13662 + * copyright notice, this list of conditions and the
13663 + * following disclaimer.
13665 + * Redistributions in binary form must reproduce the above
13666 + * copyright notice, this list of conditions and the following
13667 + * disclaimer in the documentation and/or other materials
13668 + * provided with the distribution.
13670 + * Neither the name of the copyright holder nor the names
13671 + * of any other contributors may be used to endorse or
13672 + * promote products derived from this software without
13673 + * specific prior written permission.
13675 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
13676 + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
13677 + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
13678 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13679 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
13680 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
13681 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
13682 + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
13683 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
13684 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
13685 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
13686 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
13687 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
13688 + * OF SUCH DAMAGE.
13691 +#include "libssh2_priv.h"
13692 +#include <errno.h>
13693 +#include <stdlib.h>
13695 +/* {{{ libssh2_scp_recv
13696 + * Open a channel and request a remote file via SCP
13698 + * NOTE: Will block in a busy loop on error. This has to be done,
13699 + * otherwise the blocking error code would erase the true
13700 + * cause of the error.
13702 +LIBSSH2_API LIBSSH2_CHANNEL *
13703 +libssh2_scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb)
13705 + int path_len = strlen(path);
13708 + if (session->scpRecv_state == libssh2_NB_state_idle) {
13709 + session->scpRecv_mode = 0;
13710 + session->scpRecv_size = 0;
13711 + session->scpRecv_mtime = 0;
13712 + session->scpRecv_atime = 0;
13714 + session->scpRecv_command_len = path_len + sizeof("scp -f ");
13717 + session->scpRecv_command_len++;
13720 + session->scpRecv_command =
13721 + LIBSSH2_ALLOC(session, session->scpRecv_command_len);
13722 + if (!session->scpRecv_command) {
13723 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
13724 + "Unable to allocate a command buffer for SCP session",
13729 + memcpy(session->scpRecv_command, "scp -pf ",
13730 + sizeof("scp -pf ") - 1);
13731 + memcpy(session->scpRecv_command + sizeof("scp -pf ") - 1, path,
13734 + memcpy(session->scpRecv_command, "scp -f ", sizeof("scp -f ") - 1);
13735 + memcpy(session->scpRecv_command + sizeof("scp -f ") - 1, path,
13738 + session->scpRecv_command[session->scpRecv_command_len - 1] = '\0';
13740 + _libssh2_debug(session, LIBSSH2_DBG_SCP,
13741 + "Opening channel for SCP receive");
13743 + session->scpRecv_state = libssh2_NB_state_created;
13746 + if (session->scpRecv_state == libssh2_NB_state_created) {
13747 + /* Allocate a channel */
13749 + session->scpRecv_channel =
13750 + libssh2_channel_open_ex(session, "session",
13751 + sizeof("session") - 1,
13752 + LIBSSH2_CHANNEL_WINDOW_DEFAULT,
13753 + LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL,
13755 + if (!session->scpRecv_channel) {
13756 + if (libssh2_session_last_errno(session) !=
13757 + LIBSSH2_ERROR_EAGAIN) {
13758 + LIBSSH2_FREE(session, session->scpRecv_command);
13759 + session->scpRecv_command = NULL;
13760 + session->scpRecv_state = libssh2_NB_state_idle;
13762 + } else if (libssh2_session_last_errno(session) ==
13763 + LIBSSH2_ERROR_EAGAIN) {
13764 + libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
13765 + "Would block starting up channel", 0);
13769 + } while (!session->scpRecv_channel);
13771 + session->scpRecv_state = libssh2_NB_state_sent;
13774 + if (session->scpRecv_state == libssh2_NB_state_sent) {
13775 + /* Request SCP for the desired file */
13776 + rc = libssh2_channel_process_startup(session->scpRecv_channel, "exec",
13777 + sizeof("exec") - 1,
13778 + (char *) session->scpRecv_command,
13779 + session->scpRecv_command_len);
13780 + if (rc == PACKET_EAGAIN) {
13781 + libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
13782 + "Would block requesting SCP startup", 0);
13785 + LIBSSH2_FREE(session, session->scpRecv_command);
13786 + session->scpRecv_command = NULL;
13787 + goto scp_recv_error;
13789 + LIBSSH2_FREE(session, session->scpRecv_command);
13790 + session->scpRecv_command = NULL;
13792 + _libssh2_debug(session, LIBSSH2_DBG_SCP, "Sending initial wakeup");
13794 + session->scpRecv_response[0] = '\0';
13796 + session->scpRecv_state = libssh2_NB_state_sent1;
13799 + if (session->scpRecv_state == libssh2_NB_state_sent1) {
13800 + rc = libssh2_channel_write_ex(session->scpRecv_channel, 0,
13801 + (char *) session->scpRecv_response, 1);
13802 + if (rc == PACKET_EAGAIN) {
13803 + libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
13804 + "Would block sending initial wakeup", 0);
13806 + } else if (rc != 1) {
13807 + goto scp_recv_error;
13810 + /* Parse SCP response */
13811 + session->scpRecv_response_len = 0;
13813 + session->scpRecv_state = libssh2_NB_state_sent2;
13816 + if ((session->scpRecv_state == libssh2_NB_state_sent2)
13817 + || (session->scpRecv_state == libssh2_NB_state_sent3)) {
13819 + && (session->scpRecv_response_len <
13820 + LIBSSH2_SCP_RESPONSE_BUFLEN)) {
13821 + unsigned char *s, *p;
13823 + if (session->scpRecv_state == libssh2_NB_state_sent2) {
13824 + rc = libssh2_channel_read_ex(session->scpRecv_channel, 0,
13825 + (char *) session->
13826 + scpRecv_response +
13827 + session->scpRecv_response_len, 1);
13828 + if (rc == PACKET_EAGAIN) {
13829 + libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
13830 + "Would block waiting for SCP response", 0);
13832 + } else if (rc <= 0) {
13833 + /* Timeout, give up */
13834 + libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
13835 + "Timed out waiting for SCP response", 0);
13836 + goto scp_recv_error;
13838 + session->scpRecv_response_len++;
13840 + if (session->scpRecv_response[0] != 'T') {
13842 + * Set this as the default error for here, if
13843 + * we are successful it will be replaced
13845 + libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
13846 + "Invalid data in SCP response, missing Time data",
13849 + session->scpRecv_err_len =
13850 + libssh2_channel_packet_data_len(session->
13851 + scpRecv_channel, 0);
13852 + session->scpRecv_err_msg =
13853 + LIBSSH2_ALLOC(session, session->scpRecv_err_len + 1);
13854 + if (!session->scpRecv_err_msg) {
13855 + goto scp_recv_error;
13857 + memset(session->scpRecv_err_msg, 0,
13858 + session->scpRecv_err_len + 1);
13860 + /* Read the remote error message */
13861 + rc = libssh2_channel_read_ex(session->scpRecv_channel, 0,
13862 + session->scpRecv_err_msg,
13863 + session->scpRecv_err_len);
13866 + * Since we have alread started reading this packet, it is
13867 + * already in the systems so it can't return PACKET_EAGAIN
13869 + LIBSSH2_FREE(session, session->scpRecv_err_msg);
13870 + session->scpRecv_err_msg = NULL;
13871 + libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
13872 + "Unknown error while getting error string",
13874 + goto scp_recv_error;
13877 + libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
13878 + session->scpRecv_err_msg, 1);
13879 + session->scpRecv_err_msg = NULL;
13880 + goto scp_recv_error;
13883 + if ((session->scpRecv_response_len > 1) &&
13885 + scpRecv_response[session->scpRecv_response_len - 1] <
13888 + scpRecv_response[session->scpRecv_response_len - 1] >
13891 + scpRecv_response[session->scpRecv_response_len - 1] !=
13894 + scpRecv_response[session->scpRecv_response_len - 1] !=
13897 + scpRecv_response[session->scpRecv_response_len - 1] !=
13899 + libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
13900 + "Invalid data in SCP response", 0);
13901 + goto scp_recv_error;
13904 + if ((session->scpRecv_response_len < 9)
13906 + scpRecv_response[session->scpRecv_response_len - 1] !=
13908 + if (session->scpRecv_response_len ==
13909 + LIBSSH2_SCP_RESPONSE_BUFLEN) {
13910 + /* You had your chance */
13911 + libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
13912 + "Unterminated response from SCP server",
13914 + goto scp_recv_error;
13916 + /* Way too short to be an SCP response, or not done yet, short circuit */
13920 + /* We're guaranteed not to go under response_len == 0 by the logic above */
13921 + while ((session->
13922 + scpRecv_response[session->scpRecv_response_len - 1] ==
13925 + scpRecv_response[session->scpRecv_response_len -
13927 + session->scpRecv_response_len--;
13928 + session->scpRecv_response[session->scpRecv_response_len] =
13931 + if (session->scpRecv_response_len < 8) {
13932 + /* EOL came too soon */
13933 + libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
13934 + "Invalid response from SCP server, too short",
13936 + goto scp_recv_error;
13939 + s = session->scpRecv_response + 1;
13941 + p = (unsigned char *) strchr((char *) s, ' ');
13942 + if (!p || ((p - s) <= 0)) {
13943 + /* No spaces or space in the wrong spot */
13944 + libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
13945 + "Invalid response from SCP server, malformed mtime",
13947 + goto scp_recv_error;
13951 + /* Make sure we don't get fooled by leftover values */
13953 + session->scpRecv_mtime = strtol((char *) s, NULL, 10);
13955 + libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
13956 + "Invalid response from SCP server, invalid mtime",
13958 + goto scp_recv_error;
13960 + s = (unsigned char *) strchr((char *) p, ' ');
13961 + if (!s || ((s - p) <= 0)) {
13962 + /* No spaces or space in the wrong spot */
13963 + libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
13964 + "Invalid response from SCP server, malformed mtime.usec",
13966 + goto scp_recv_error;
13969 + /* Ignore mtime.usec */
13971 + p = (unsigned char *) strchr((char *) s, ' ');
13972 + if (!p || ((p - s) <= 0)) {
13973 + /* No spaces or space in the wrong spot */
13974 + libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
13975 + "Invalid response from SCP server, too short or malformed",
13977 + goto scp_recv_error;
13981 + /* Make sure we don't get fooled by leftover values */
13983 + session->scpRecv_atime = strtol((char *) s, NULL, 10);
13985 + libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
13986 + "Invalid response from SCP server, invalid atime",
13988 + goto scp_recv_error;
13992 + session->scpRecv_response[0] = '\0';
13994 + session->scpRecv_state = libssh2_NB_state_sent3;
13997 + if (session->scpRecv_state == libssh2_NB_state_sent3) {
13998 + rc = libssh2_channel_write_ex(session->scpRecv_channel, 0,
13999 + (char *) session->
14000 + scpRecv_response, 1);
14001 + if (rc == PACKET_EAGAIN) {
14002 + libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
14003 + "Would block waiting to send SCP ACK", 0);
14005 + } else if (rc != 1) {
14006 + goto scp_recv_error;
14009 + _libssh2_debug(session, LIBSSH2_DBG_SCP,
14010 + "mtime = %ld, atime = %ld",
14011 + session->scpRecv_mtime, session->scpRecv_atime);
14013 + /* We *should* check that atime.usec is valid, but why let that stop use? */
14018 + session->scpRecv_state = libssh2_NB_state_sent4;
14021 + if (session->scpRecv_state == libssh2_NB_state_sent4) {
14022 + session->scpRecv_response_len = 0;
14024 + session->scpRecv_state = libssh2_NB_state_sent5;
14027 + if ((session->scpRecv_state == libssh2_NB_state_sent5)
14028 + || (session->scpRecv_state == libssh2_NB_state_sent6)) {
14029 + while (session->scpRecv_response_len < LIBSSH2_SCP_RESPONSE_BUFLEN) {
14030 + char *s, *p, *e = NULL;
14032 + if (session->scpRecv_state == libssh2_NB_state_sent5) {
14033 + rc = libssh2_channel_read_ex(session->scpRecv_channel, 0,
14034 + (char *) session->
14035 + scpRecv_response +
14036 + session->scpRecv_response_len, 1);
14037 + if (rc == PACKET_EAGAIN) {
14038 + libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
14039 + "Would block waiting for SCP response", 0);
14041 + } else if (rc <= 0) {
14042 + /* Timeout, give up */
14043 + libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
14044 + "Timed out waiting for SCP response", 0);
14045 + goto scp_recv_error;
14047 + session->scpRecv_response_len++;
14049 + if (session->scpRecv_response[0] != 'C') {
14050 + libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
14051 + "Invalid response from SCP server", 0);
14052 + goto scp_recv_error;
14055 + if ((session->scpRecv_response_len > 1) &&
14057 + scpRecv_response[session->scpRecv_response_len - 1] !=
14060 + scpRecv_response[session->scpRecv_response_len - 1] !=
14064 + scpRecv_response[session->scpRecv_response_len - 1] < 32)
14066 + scpRecv_response[session->scpRecv_response_len - 1] >
14068 + libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
14069 + "Invalid data in SCP response", 0);
14070 + goto scp_recv_error;
14073 + if ((session->scpRecv_response_len < 7)
14075 + scpRecv_response[session->scpRecv_response_len - 1] !=
14077 + if (session->scpRecv_response_len ==
14078 + LIBSSH2_SCP_RESPONSE_BUFLEN) {
14079 + /* You had your chance */
14080 + libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
14081 + "Unterminated response from SCP server",
14083 + goto scp_recv_error;
14085 + /* Way too short to be an SCP response, or not done yet, short circuit */
14089 + /* We're guaranteed not to go under response_len == 0 by the logic above */
14090 + while ((session->
14091 + scpRecv_response[session->scpRecv_response_len - 1] ==
14094 + scpRecv_response[session->scpRecv_response_len -
14096 + session->scpRecv_response_len--;
14098 + session->scpRecv_response[session->scpRecv_response_len] =
14101 + if (session->scpRecv_response_len < 6) {
14102 + /* EOL came too soon */
14103 + libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
14104 + "Invalid response from SCP server, too short",
14106 + goto scp_recv_error;
14109 + s = (char *) session->scpRecv_response + 1;
14111 + p = strchr(s, ' ');
14112 + if (!p || ((p - s) <= 0)) {
14113 + /* No spaces or space in the wrong spot */
14114 + libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
14115 + "Invalid response from SCP server, malformed mode",
14117 + goto scp_recv_error;
14121 + /* Make sure we don't get fooled by leftover values */
14123 + session->scpRecv_mode = strtol(s, &e, 8);
14124 + if ((e && *e) || errno) {
14125 + libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
14126 + "Invalid response from SCP server, invalid mode",
14128 + goto scp_recv_error;
14131 + s = strchr(p, ' ');
14132 + if (!s || ((s - p) <= 0)) {
14133 + /* No spaces or space in the wrong spot */
14134 + libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
14135 + "Invalid response from SCP server, too short or malformed",
14137 + goto scp_recv_error;
14141 + /* Make sure we don't get fooled by leftover values */
14143 + session->scpRecv_size = scpsize_strtol(p, &e, 10);
14144 + if ((e && *e) || errno) {
14145 + libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
14146 + "Invalid response from SCP server, invalid size",
14148 + goto scp_recv_error;
14152 + session->scpRecv_response[0] = '\0';
14154 + session->scpRecv_state = libssh2_NB_state_sent6;
14157 + if (session->scpRecv_state == libssh2_NB_state_sent6) {
14158 + rc = libssh2_channel_write_ex(session->scpRecv_channel, 0,
14159 + (char *) session->
14160 + scpRecv_response, 1);
14161 + if (rc == PACKET_EAGAIN) {
14162 + libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
14163 + "Would block sending SCP ACK", 0);
14165 + } else if (rc != 1) {
14166 + goto scp_recv_error;
14168 + _libssh2_debug(session, LIBSSH2_DBG_SCP,
14169 + "mode = 0%lo size = %ld", session->scpRecv_mode,
14170 + session->scpRecv_size);
14172 + /* We *should* check that basename is valid, but why let that stop us? */
14177 + session->scpRecv_state = libssh2_NB_state_sent7;
14181 + memset(sb, 0, sizeof(struct stat));
14183 + sb->st_mtime = session->scpRecv_mtime;
14184 + sb->st_atime = session->scpRecv_atime;
14185 + sb->st_size = session->scpRecv_size;
14186 + sb->st_mode = session->scpRecv_mode;
14189 + session->scpRecv_state = libssh2_NB_state_idle;
14190 + return session->scpRecv_channel;
14193 + while (libssh2_channel_free(session->scpRecv_channel) == PACKET_EAGAIN);
14194 + session->scpRecv_channel = NULL;
14195 + session->scpRecv_state = libssh2_NB_state_idle;
14201 +/* {{{ libssh2_scp_send_ex
14202 + * Send a file using SCP
14204 + * NOTE: Will block in a busy loop on error. This has to be done,
14205 + * otherwise the blocking error code would erase the true
14206 + * cause of the error.
14208 +LIBSSH2_API LIBSSH2_CHANNEL *
14209 +libssh2_scp_send_ex(LIBSSH2_SESSION * session, const char *path, int mode,
14210 + size_t size, long mtime, long atime)
14212 + int path_len = strlen(path);
14213 + unsigned const char *base;
14216 + if (session->scpSend_state == libssh2_NB_state_idle) {
14217 + session->scpSend_command_len = path_len + sizeof("scp -t ");
14219 + if (mtime || atime) {
14220 + session->scpSend_command_len++;
14223 + session->scpSend_command =
14224 + LIBSSH2_ALLOC(session, session->scpSend_command_len);
14225 + if (!session->scpSend_command) {
14226 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
14227 + "Unable to allocate a command buffer for scp session",
14232 + if (mtime || atime) {
14233 + memcpy(session->scpSend_command, "scp -pt ",
14234 + sizeof("scp -pt ") - 1);
14235 + memcpy(session->scpSend_command + sizeof("scp -pt ") - 1, path,
14238 + memcpy(session->scpSend_command, "scp -t ", sizeof("scp -t ") - 1);
14239 + memcpy(session->scpSend_command + sizeof("scp -t ") - 1, path,
14242 + session->scpSend_command[session->scpSend_command_len - 1] = '\0';
14244 + _libssh2_debug(session, LIBSSH2_DBG_SCP,
14245 + "Opening channel for SCP send");
14246 + /* Allocate a channel */
14248 + session->scpSend_state = libssh2_NB_state_created;
14251 + if (session->scpSend_state == libssh2_NB_state_created) {
14252 + session->scpSend_channel =
14253 + libssh2_channel_open_ex(session, "session", sizeof("session") - 1,
14254 + LIBSSH2_CHANNEL_WINDOW_DEFAULT,
14255 + LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0);
14256 + if (!session->scpSend_channel) {
14257 + if (libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN) {
14258 + /* previous call set libssh2_session_last_error(), pass it through */
14259 + LIBSSH2_FREE(session, session->scpSend_command);
14260 + session->scpSend_command = NULL;
14261 + session->scpSend_state = libssh2_NB_state_idle;
14263 + } else if (libssh2_session_last_errno(session) ==
14264 + LIBSSH2_ERROR_EAGAIN) {
14265 + libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
14266 + "Would block starting up channel", 0);
14271 + session->scpSend_state = libssh2_NB_state_sent;
14274 + if (session->scpSend_state == libssh2_NB_state_sent) {
14275 + /* Request SCP for the desired file */
14276 + rc = libssh2_channel_process_startup(session->scpSend_channel, "exec",
14277 + sizeof("exec") - 1,
14278 + (char *) session->scpSend_command,
14279 + session->scpSend_command_len);
14280 + if (rc == PACKET_EAGAIN) {
14281 + libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
14282 + "Would block requesting SCP startup", 0);
14285 + /* previous call set libssh2_session_last_error(), pass it through */
14286 + LIBSSH2_FREE(session, session->scpSend_command);
14287 + session->scpSend_command = NULL;
14288 + libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
14289 + "Unknown error while getting error string", 0);
14290 + goto scp_send_error;
14292 + LIBSSH2_FREE(session, session->scpSend_command);
14293 + session->scpSend_command = NULL;
14295 + session->scpSend_state = libssh2_NB_state_sent1;
14298 + if (session->scpSend_state == libssh2_NB_state_sent1) {
14299 + /* Wait for ACK */
14300 + rc = libssh2_channel_read_ex(session->scpSend_channel, 0,
14301 + (char *) session->scpSend_response, 1);
14302 + if (rc == PACKET_EAGAIN) {
14303 + libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
14304 + "Would block waiting for response from remote", 0);
14306 + } else if ((rc <= 0) || (session->scpSend_response[0] != 0)) {
14307 + libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
14308 + "Invalid ACK response from remote", 0);
14309 + goto scp_send_error;
14312 + if (mtime || atime) {
14313 + /* Send mtime and atime to be used for file */
14314 + session->scpSend_response_len =
14315 + snprintf((char *) session->scpSend_response,
14316 + LIBSSH2_SCP_RESPONSE_BUFLEN, "T%ld 0 %ld 0\n", mtime,
14318 + _libssh2_debug(session, LIBSSH2_DBG_SCP, "Sent %s",
14319 + session->scpSend_response);
14322 + session->scpSend_state = libssh2_NB_state_sent2;
14325 + /* Send mtime and atime to be used for file */
14326 + if (mtime || atime) {
14327 + if (session->scpSend_state == libssh2_NB_state_sent2) {
14328 + rc = libssh2_channel_write_ex(session->scpSend_channel, 0,
14329 + (char *) session->scpSend_response,
14330 + session->scpSend_response_len);
14331 + if (rc == PACKET_EAGAIN) {
14332 + libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
14333 + "Would block sending time data for SCP file", 0);
14335 + } else if (rc != session->scpSend_response_len) {
14336 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
14337 + "Unable to send time data for SCP file", 0);
14338 + goto scp_send_error;
14341 + session->scpSend_state = libssh2_NB_state_sent3;
14344 + if (session->scpSend_state == libssh2_NB_state_sent3) {
14345 + /* Wait for ACK */
14346 + rc = libssh2_channel_read_ex(session->scpSend_channel, 0,
14347 + (char *) session->scpSend_response,
14349 + if (rc == PACKET_EAGAIN) {
14350 + libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
14351 + "Would block waiting for response", 0);
14353 + } else if ((rc <= 0) || (session->scpSend_response[0] != 0)) {
14354 + libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
14355 + "Invalid ACK response from remote", 0);
14356 + goto scp_send_error;
14359 + session->scpSend_state = libssh2_NB_state_sent4;
14362 + if (session->scpSend_state == libssh2_NB_state_sent2) {
14363 + session->scpSend_state = libssh2_NB_state_sent4;
14367 + if (session->scpSend_state == libssh2_NB_state_sent4) {
14368 + /* Send mode, size, and basename */
14369 + base = (unsigned char *) strrchr(path, '/');
14373 + base = (unsigned char *) path;
14376 + session->scpSend_response_len =
14377 + snprintf((char *) session->scpSend_response,
14378 + LIBSSH2_SCP_RESPONSE_BUFLEN, "C0%o %lu %s\n", mode,
14379 + (unsigned long) size, base);
14380 + _libssh2_debug(session, LIBSSH2_DBG_SCP, "Sent %s",
14381 + session->scpSend_response);
14383 + session->scpSend_state = libssh2_NB_state_sent5;
14386 + if (session->scpSend_state == libssh2_NB_state_sent5) {
14387 + rc = libssh2_channel_write_ex(session->scpSend_channel, 0,
14388 + (char *) session->scpSend_response,
14389 + session->scpSend_response_len);
14390 + if (rc == PACKET_EAGAIN) {
14391 + libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
14392 + "Would block send core file data for SCP file", 0);
14394 + } else if (rc != session->scpSend_response_len) {
14395 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
14396 + "Unable to send core file data for SCP file", 0);
14397 + goto scp_send_error;
14400 + session->scpSend_state = libssh2_NB_state_sent6;
14403 + if (session->scpSend_state == libssh2_NB_state_sent6) {
14404 + /* Wait for ACK */
14405 + rc = libssh2_channel_read_ex(session->scpSend_channel, 0,
14406 + (char *) session->scpSend_response, 1);
14407 + if (rc == PACKET_EAGAIN) {
14408 + libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
14409 + "Would block waiting for response", 0);
14411 + } else if (rc <= 0) {
14412 + libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
14413 + "Invalid ACK response from remote", 0);
14414 + goto scp_send_error;
14415 + } else if (session->scpSend_response[0] != 0) {
14417 + * Set this as the default error for here, if
14418 + * we are successful it will be replaced
14420 + libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
14421 + "Invalid ACK response from remote", 0);
14423 + session->scpSend_err_len =
14424 + libssh2_channel_packet_data_len(session->scpSend_channel, 0);
14425 + session->scpSend_err_msg =
14426 + LIBSSH2_ALLOC(session, session->scpSend_err_len + 1);
14427 + if (!session->scpSend_err_msg) {
14428 + goto scp_send_error;
14430 + memset(session->scpSend_err_msg, 0, session->scpSend_err_len + 1);
14432 + /* Read the remote error message */
14433 + rc = libssh2_channel_read_ex(session->scpSend_channel, 0,
14434 + session->scpSend_err_msg,
14435 + session->scpSend_err_len);
14438 + * Since we have alread started reading this packet, it is
14439 + * already in the systems so it can't return PACKET_EAGAIN
14441 + LIBSSH2_FREE(session, session->scpSend_err_msg);
14442 + session->scpSend_err_msg = NULL;
14443 + goto scp_send_error;
14446 + libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
14447 + session->scpSend_err_msg, 1);
14448 + session->scpSend_err_msg = NULL;
14449 + goto scp_send_error;
14453 + session->scpSend_state = libssh2_NB_state_idle;
14455 + return session->scpSend_channel;
14458 + while (libssh2_channel_free(session->scpSend_channel) == PACKET_EAGAIN);
14459 + session->scpSend_channel = NULL;
14460 + session->scpSend_state = libssh2_NB_state_idle;
14466 Property changes on: libssh2/src/scp.c
14467 ___________________________________________________________________
14468 Added: svn:mime-type
14470 Added: svn:keywords
14471 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
14472 Added: cvs2svn:cvs-rev
14474 Added: svn:eol-style
14477 Index: libssh2/src/hostkey.c
14478 ===================================================================
14479 --- libssh2/src/hostkey.c (.../tags/RELEASE_0_11_0)
14480 +++ libssh2/src/hostkey.c (.../trunk)
14482 +/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
14483 + * All rights reserved.
14485 + * Redistribution and use in source and binary forms,
14486 + * with or without modification, are permitted provided
14487 + * that the following conditions are met:
14489 + * Redistributions of source code must retain the above
14490 + * copyright notice, this list of conditions and the
14491 + * following disclaimer.
14493 + * Redistributions in binary form must reproduce the above
14494 + * copyright notice, this list of conditions and the following
14495 + * disclaimer in the documentation and/or other materials
14496 + * provided with the distribution.
14498 + * Neither the name of the copyright holder nor the names
14499 + * of any other contributors may be used to endorse or
14500 + * promote products derived from this software without
14501 + * specific prior written permission.
14503 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
14504 + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
14505 + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
14506 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
14507 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
14508 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
14509 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
14510 + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
14511 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
14512 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
14513 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
14514 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
14515 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
14516 + * OF SUCH DAMAGE.
14519 +#include "libssh2_priv.h"
14521 +/* Needed for struct iovec on some platforms */
14522 +#ifdef HAVE_SYS_UIO_H
14523 +#include <sys/uio.h>
14531 +static int libssh2_hostkey_method_ssh_rsa_dtor(LIBSSH2_SESSION * session,
14532 + void **abstract);
14534 +/* {{{ libssh2_hostkey_method_ssh_rsa_init
14535 + * Initialize the server hostkey working area with e/n pair
14538 +libssh2_hostkey_method_ssh_rsa_init(LIBSSH2_SESSION * session,
14539 + const unsigned char *hostkey_data,
14540 + unsigned long hostkey_data_len,
14543 + libssh2_rsa_ctx *rsactx;
14544 + const unsigned char *s, *e, *n;
14545 + unsigned long len, e_len, n_len;
14547 + (void) hostkey_data_len;
14550 + libssh2_hostkey_method_ssh_rsa_dtor(session, abstract);
14551 + *abstract = NULL;
14554 + s = hostkey_data;
14555 + len = libssh2_ntohu32(s);
14558 + if (len != 7 || strncmp((char *) s, "ssh-rsa", 7) != 0) {
14563 + e_len = libssh2_ntohu32(s);
14568 + n_len = libssh2_ntohu32(s);
14573 + if (_libssh2_rsa_new(&rsactx, e, e_len, n, n_len, NULL, 0,
14574 + NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0))
14577 + *abstract = rsactx;
14584 +/* {{{ libssh2_hostkey_method_ssh_rsa_initPEM
14585 + * Load a Private Key from a PEM file
14588 +libssh2_hostkey_method_ssh_rsa_initPEM(LIBSSH2_SESSION * session,
14589 + const char *privkeyfile,
14590 + unsigned const char *passphrase,
14593 + libssh2_rsa_ctx *rsactx;
14598 + libssh2_hostkey_method_ssh_rsa_dtor(session, abstract);
14599 + *abstract = NULL;
14602 + fp = fopen(privkeyfile, "r");
14607 + ret = _libssh2_rsa_new_private(&rsactx, session, fp, passphrase);
14613 + *abstract = rsactx;
14620 +/* {{{ libssh2_hostkey_method_ssh_rsa_sign
14621 + * Verify signature created by remote
14624 +libssh2_hostkey_method_ssh_rsa_sig_verify(LIBSSH2_SESSION * session,
14625 + const unsigned char *sig,
14626 + unsigned long sig_len,
14627 + const unsigned char *m,
14628 + unsigned long m_len, void **abstract)
14630 + libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract);
14633 + /* Skip past keyname_len(4) + keyname(7){"ssh-rsa"} + signature_len(4) */
14636 + return _libssh2_rsa_sha1_verify(rsactx, sig, sig_len, m, m_len);
14641 +/* {{{ libssh2_hostkey_method_ssh_rsa_signv
14642 + * Construct a signature from an array of vectors
14645 +libssh2_hostkey_method_ssh_rsa_signv(LIBSSH2_SESSION * session,
14646 + unsigned char **signature,
14647 + unsigned long *signature_len,
14648 + unsigned long veccount,
14649 + const struct iovec datavec[],
14652 + libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract);
14655 + unsigned char hash[SHA_DIGEST_LENGTH];
14656 + libssh2_sha1_ctx ctx;
14658 + libssh2_sha1_init(&ctx);
14659 + for(i = 0; i < veccount; i++) {
14660 + libssh2_sha1_update(ctx, datavec[i].iov_base, datavec[i].iov_len);
14662 + libssh2_sha1_final(ctx, hash);
14664 + ret = _libssh2_rsa_sha1_sign(session, rsactx, hash, SHA_DIGEST_LENGTH,
14665 + signature, signature_len);
14675 +/* {{{ libssh2_hostkey_method_ssh_rsa_dtor
14676 + * Shutdown the hostkey
14679 +libssh2_hostkey_method_ssh_rsa_dtor(LIBSSH2_SESSION * session, void **abstract)
14681 + libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract);
14684 + _libssh2_rsa_free(rsactx);
14686 + *abstract = NULL;
14693 +static const LIBSSH2_HOSTKEY_METHOD libssh2_hostkey_method_ssh_rsa = {
14695 + MD5_DIGEST_LENGTH,
14696 + libssh2_hostkey_method_ssh_rsa_init,
14697 + libssh2_hostkey_method_ssh_rsa_initPEM,
14698 + libssh2_hostkey_method_ssh_rsa_sig_verify,
14699 + libssh2_hostkey_method_ssh_rsa_signv,
14700 + NULL, /* encrypt */
14701 + libssh2_hostkey_method_ssh_rsa_dtor,
14703 +#endif /* LIBSSH2_RSA */
14710 +static int libssh2_hostkey_method_ssh_dss_dtor(LIBSSH2_SESSION * session,
14711 + void **abstract);
14713 +/* {{{ libssh2_hostkey_method_ssh_dss_init
14714 + * Initialize the server hostkey working area with p/q/g/y set
14717 +libssh2_hostkey_method_ssh_dss_init(LIBSSH2_SESSION * session,
14718 + const unsigned char *hostkey_data,
14719 + unsigned long hostkey_data_len,
14722 + libssh2_dsa_ctx *dsactx;
14723 + const unsigned char *p, *q, *g, *y, *s;
14724 + unsigned long p_len, q_len, g_len, y_len, len;
14725 + (void) hostkey_data_len;
14728 + libssh2_hostkey_method_ssh_dss_dtor(session, abstract);
14729 + *abstract = NULL;
14732 + s = hostkey_data;
14733 + len = libssh2_ntohu32(s);
14735 + if (len != 7 || strncmp((char *) s, "ssh-dss", 7) != 0) {
14740 + p_len = libssh2_ntohu32(s);
14744 + q_len = libssh2_ntohu32(s);
14748 + g_len = libssh2_ntohu32(s);
14752 + y_len = libssh2_ntohu32(s);
14757 + _libssh2_dsa_new(&dsactx, p, p_len, q, q_len, g, g_len, y, y_len, NULL, 0);
14759 + *abstract = dsactx;
14766 +/* {{{ libssh2_hostkey_method_ssh_dss_initPEM
14767 + * Load a Private Key from a PEM file
14770 +libssh2_hostkey_method_ssh_dss_initPEM(LIBSSH2_SESSION * session,
14771 + const char *privkeyfile,
14772 + unsigned const char *passphrase,
14775 + libssh2_dsa_ctx *dsactx;
14780 + libssh2_hostkey_method_ssh_dss_dtor(session, abstract);
14781 + *abstract = NULL;
14784 + fp = fopen(privkeyfile, "r");
14789 + ret = _libssh2_dsa_new_private(&dsactx, session, fp, passphrase);
14795 + *abstract = dsactx;
14802 +/* {{{ libssh2_hostkey_method_ssh_dss_sign
14803 + * Verify signature created by remote
14806 +libssh2_hostkey_method_ssh_dss_sig_verify(LIBSSH2_SESSION * session,
14807 + const unsigned char *sig,
14808 + unsigned long sig_len,
14809 + const unsigned char *m,
14810 + unsigned long m_len, void **abstract)
14812 + libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx *) (*abstract);
14814 + /* Skip past keyname_len(4) + keyname(7){"ssh-dss"} + signature_len(4) */
14817 + if (sig_len != 40) {
14818 + libssh2_error(session, LIBSSH2_ERROR_PROTO,
14819 + "Invalid DSS signature length", 0);
14822 + return _libssh2_dsa_sha1_verify(dsactx, sig, m, m_len);
14827 +/* {{{ libssh2_hostkey_method_ssh_dss_signv
14828 + * Construct a signature from an array of vectors
14831 +libssh2_hostkey_method_ssh_dss_signv(LIBSSH2_SESSION * session,
14832 + unsigned char **signature,
14833 + unsigned long *signature_len,
14834 + unsigned long veccount,
14835 + const struct iovec datavec[],
14838 + libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx *) (*abstract);
14839 + unsigned char hash[SHA_DIGEST_LENGTH];
14840 + libssh2_sha1_ctx ctx;
14843 + *signature = LIBSSH2_ALLOC(session, 2 * SHA_DIGEST_LENGTH);
14844 + if (!*signature) {
14848 + *signature_len = 2 * SHA_DIGEST_LENGTH;
14849 + memset(*signature, 0, 2 * SHA_DIGEST_LENGTH);
14851 + libssh2_sha1_init(&ctx);
14852 + for(i = 0; i < veccount; i++) {
14853 + libssh2_sha1_update(ctx, datavec[i].iov_base, datavec[i].iov_len);
14855 + libssh2_sha1_final(ctx, hash);
14857 + if (_libssh2_dsa_sha1_sign(dsactx, hash, SHA_DIGEST_LENGTH, *signature)) {
14858 + LIBSSH2_FREE(session, *signature);
14867 +/* {{{ libssh2_hostkey_method_ssh_dss_dtor
14868 + * Shutdown the hostkey method
14871 +libssh2_hostkey_method_ssh_dss_dtor(LIBSSH2_SESSION * session, void **abstract)
14873 + libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx *) (*abstract);
14876 + _libssh2_dsa_free(dsactx);
14878 + *abstract = NULL;
14885 +static const LIBSSH2_HOSTKEY_METHOD libssh2_hostkey_method_ssh_dss = {
14887 + MD5_DIGEST_LENGTH,
14888 + libssh2_hostkey_method_ssh_dss_init,
14889 + libssh2_hostkey_method_ssh_dss_initPEM,
14890 + libssh2_hostkey_method_ssh_dss_sig_verify,
14891 + libssh2_hostkey_method_ssh_dss_signv,
14892 + NULL, /* encrypt */
14893 + libssh2_hostkey_method_ssh_dss_dtor,
14895 +#endif /* LIBSSH2_DSA */
14897 +static const LIBSSH2_HOSTKEY_METHOD *_libssh2_hostkey_methods[] = {
14899 + &libssh2_hostkey_method_ssh_rsa,
14900 +#endif /* LIBSSH2_RSA */
14902 + &libssh2_hostkey_method_ssh_dss,
14903 +#endif /* LIBSSH2_DSA */
14907 +const LIBSSH2_HOSTKEY_METHOD **
14908 +libssh2_hostkey_methods(void)
14910 + return _libssh2_hostkey_methods;
14913 +/* {{{ libssh2_hostkey_hash
14914 + * Returns hash signature
14915 + * Returned buffer should NOT be freed
14916 + * Length of buffer is determined by hash type
14917 + * i.e. MD5 == 16, SHA1 == 20
14919 +LIBSSH2_API const char *
14920 +libssh2_hostkey_hash(LIBSSH2_SESSION * session, int hash_type)
14922 + switch (hash_type) {
14924 + case LIBSSH2_HOSTKEY_HASH_MD5:
14925 + return (char *) session->server_hostkey_md5;
14927 +#endif /* LIBSSH2_MD5 */
14928 + case LIBSSH2_HOSTKEY_HASH_SHA1:
14929 + return (char *) session->server_hostkey_sha1;
14938 Property changes on: libssh2/src/hostkey.c
14939 ___________________________________________________________________
14940 Added: svn:mime-type
14942 Added: svn:keywords
14943 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
14944 Added: cvs2svn:cvs-rev
14946 Added: svn:eol-style
14949 Index: libssh2/src/publickey.c
14950 ===================================================================
14951 --- libssh2/src/publickey.c (.../tags/RELEASE_0_11_0)
14952 +++ libssh2/src/publickey.c (.../trunk)
14954 +/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
14955 + * All rights reserved.
14957 + * Redistribution and use in source and binary forms,
14958 + * with or without modification, are permitted provided
14959 + * that the following conditions are met:
14961 + * Redistributions of source code must retain the above
14962 + * copyright notice, this list of conditions and the
14963 + * following disclaimer.
14965 + * Redistributions in binary form must reproduce the above
14966 + * copyright notice, this list of conditions and the following
14967 + * disclaimer in the documentation and/or other materials
14968 + * provided with the distribution.
14970 + * Neither the name of the copyright holder nor the names
14971 + * of any other contributors may be used to endorse or
14972 + * promote products derived from this software without
14973 + * specific prior written permission.
14975 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
14976 + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
14977 + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
14978 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
14979 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
14980 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
14981 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
14982 + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
14983 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
14984 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
14985 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
14986 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
14987 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
14988 + * OF SUCH DAMAGE.
14991 +#include "libssh2_priv.h"
14992 +#include "libssh2_publickey.h"
14994 +#define LIBSSH2_PUBLICKEY_VERSION 2
14996 +/* Numericised response codes -- Not IETF standard, just a local representation */
14997 +#define LIBSSH2_PUBLICKEY_RESPONSE_STATUS 0
14998 +#define LIBSSH2_PUBLICKEY_RESPONSE_VERSION 1
14999 +#define LIBSSH2_PUBLICKEY_RESPONSE_PUBLICKEY 2
15001 +typedef struct _LIBSSH2_PUBLICKEY_CODE_LIST
15004 + const char *name;
15006 +} LIBSSH2_PUBLICKEY_CODE_LIST;
15008 +static const LIBSSH2_PUBLICKEY_CODE_LIST libssh2_publickey_response_codes[] = {
15009 + {LIBSSH2_PUBLICKEY_RESPONSE_STATUS, "status", sizeof("status") - 1}
15011 + {LIBSSH2_PUBLICKEY_RESPONSE_VERSION, "version", sizeof("version") - 1}
15013 + {LIBSSH2_PUBLICKEY_RESPONSE_PUBLICKEY, "publickey", sizeof("publickey") - 1}
15018 +/* PUBLICKEY status codes -- IETF defined */
15019 +#define LIBSSH2_PUBLICKEY_SUCCESS 0
15020 +#define LIBSSH2_PUBLICKEY_ACCESS_DENIED 1
15021 +#define LIBSSH2_PUBLICKEY_STORAGE_EXCEEDED 2
15022 +#define LIBSSH2_PUBLICKEY_VERSION_NOT_SUPPORTED 3
15023 +#define LIBSSH2_PUBLICKEY_KEY_NOT_FOUND 4
15024 +#define LIBSSH2_PUBLICKEY_KEY_NOT_SUPPORTED 5
15025 +#define LIBSSH2_PUBLICKEY_KEY_ALREADY_PRESENT 6
15026 +#define LIBSSH2_PUBLICKEY_GENERAL_FAILURE 7
15027 +#define LIBSSH2_PUBLICKEY_REQUEST_NOT_SUPPORTED 8
15029 +#define LIBSSH2_PUBLICKEY_STATUS_CODE_MAX 8
15031 +static const LIBSSH2_PUBLICKEY_CODE_LIST libssh2_publickey_status_codes[] = {
15032 + {LIBSSH2_PUBLICKEY_SUCCESS, "success", sizeof("success") - 1}
15034 + {LIBSSH2_PUBLICKEY_ACCESS_DENIED, "access denied",
15035 + sizeof("access denied") - 1}
15037 + {LIBSSH2_PUBLICKEY_STORAGE_EXCEEDED, "storage exceeded",
15038 + sizeof("storage exceeded") - 1}
15040 + {LIBSSH2_PUBLICKEY_VERSION_NOT_SUPPORTED, "version not supported",
15041 + sizeof("version not supported") - 1}
15043 + {LIBSSH2_PUBLICKEY_KEY_NOT_FOUND, "key not found",
15044 + sizeof("key not found") - 1}
15046 + {LIBSSH2_PUBLICKEY_KEY_NOT_SUPPORTED, "key not supported",
15047 + sizeof("key not supported") - 1}
15049 + {LIBSSH2_PUBLICKEY_KEY_ALREADY_PRESENT, "key already present",
15050 + sizeof("key already present") - 1}
15052 + {LIBSSH2_PUBLICKEY_GENERAL_FAILURE, "general failure",
15053 + sizeof("general failure") - 1}
15055 + {LIBSSH2_PUBLICKEY_REQUEST_NOT_SUPPORTED, "request not supported",
15056 + sizeof("request not supported") - 1}
15061 +/* {{{ libssh2_publickey_status_error
15062 + * Format an error message from a status code
15064 +#define LIBSSH2_PUBLICKEY_STATUS_TEXT_START "Publickey Subsystem Error: \""
15065 +#define LIBSSH2_PUBLICKEY_STATUS_TEXT_MID "\" Server Reports: \""
15066 +#define LIBSSH2_PUBLICKEY_STATUS_TEXT_END "\""
15068 +libssh2_publickey_status_error(const LIBSSH2_PUBLICKEY * pkey,
15069 + LIBSSH2_SESSION * session, int status,
15070 + const unsigned char *message, int message_len)
15072 + const char *status_text;
15073 + int status_text_len;
15077 + /* GENERAL_FAILURE got remapped between version 1 and 2 */
15078 + if (status == 6 && pkey && pkey->version == 1) {
15082 + if (status < 0 || status > LIBSSH2_PUBLICKEY_STATUS_CODE_MAX) {
15083 + status_text = "unknown";
15084 + status_text_len = sizeof("unknown") - 1;
15086 + status_text = libssh2_publickey_status_codes[status].name;
15087 + status_text_len = libssh2_publickey_status_codes[status].name_len;
15091 + (sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_START) - 1) + status_text_len +
15092 + (sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_MID) - 1) + message_len +
15093 + (sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_END) - 1);
15094 + m = LIBSSH2_ALLOC(session, m_len + 1);
15096 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
15097 + "Unable to allocate memory for status message", 0);
15101 + memcpy(s, LIBSSH2_PUBLICKEY_STATUS_TEXT_START,
15102 + sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_START) - 1);
15103 + s += sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_START) - 1;
15104 + memcpy(s, status_text, status_text_len);
15105 + s += status_text_len;
15106 + memcpy(s, LIBSSH2_PUBLICKEY_STATUS_TEXT_MID,
15107 + sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_MID) - 1);
15108 + s += sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_MID) - 1;
15109 + memcpy(s, message, message_len);
15110 + s += message_len;
15111 + memcpy(s, LIBSSH2_PUBLICKEY_STATUS_TEXT_END,
15112 + sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_END) - 1);
15113 + s += sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_END);
15114 + libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, m, 1);
15119 +/* {{{ libssh2_publickey_packet_receive
15120 + * Read a packet from the subsystem
15123 +libssh2_publickey_packet_receive(LIBSSH2_PUBLICKEY * pkey,
15124 + unsigned char **data, unsigned long *data_len)
15126 + LIBSSH2_CHANNEL *channel = pkey->channel;
15127 + LIBSSH2_SESSION *session = channel->session;
15128 + unsigned char buffer[4];
15131 + if (pkey->receive_state == libssh2_NB_state_idle) {
15132 + rc = libssh2_channel_read_ex(channel, 0, (char *) buffer, 4);
15133 + if (rc == PACKET_EAGAIN) {
15134 + return PACKET_EAGAIN;
15135 + } else if (rc != 4) {
15136 + libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
15137 + "Invalid response from publickey subsystem", 0);
15141 + pkey->receive_packet_len = libssh2_ntohu32(buffer);
15142 + pkey->receive_packet =
15143 + LIBSSH2_ALLOC(session, pkey->receive_packet_len);
15144 + if (!pkey->receive_packet) {
15145 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
15146 + "Unable to allocate publickey response buffer", 0);
15150 + pkey->receive_state = libssh2_NB_state_sent;
15153 + if (pkey->receive_state == libssh2_NB_state_sent) {
15154 + rc = libssh2_channel_read_ex(channel, 0, (char *) pkey->receive_packet,
15155 + pkey->receive_packet_len);
15156 + if (rc == PACKET_EAGAIN) {
15157 + return PACKET_EAGAIN;
15158 + } else if (rc != (int)pkey->receive_packet_len) {
15159 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
15160 + "Timeout waiting for publickey subsystem response packet",
15162 + LIBSSH2_FREE(session, pkey->receive_packet);
15163 + pkey->receive_packet = NULL;
15164 + pkey->receive_state = libssh2_NB_state_idle;
15168 + *data = pkey->receive_packet;
15169 + *data_len = pkey->receive_packet_len;
15172 + pkey->receive_state = libssh2_NB_state_idle;
15179 +/* {{{ libssh2_publickey_response_id
15180 + * Translate a string response name to a numeric code
15181 + * Data will be incremented by 4 + response_len on success only
15184 +libssh2_publickey_response_id(unsigned char **pdata, int data_len)
15186 + unsigned long response_len;
15187 + unsigned char *data = *pdata;
15188 + const LIBSSH2_PUBLICKEY_CODE_LIST *codes =
15189 + libssh2_publickey_response_codes;
15191 + if (data_len < 4) {
15192 + /* Malformed response */
15195 + response_len = libssh2_ntohu32(data);
15198 + if (data_len < (int)response_len) {
15199 + /* Malformed response */
15203 + while (codes->name) {
15204 + if ((unsigned long)codes->name_len == response_len &&
15205 + strncmp(codes->name, (char *) data, response_len) == 0) {
15206 + *pdata = data + response_len;
15207 + return codes->code;
15217 +/* {{{ libssh2_publickey_response_success
15218 + * Generic helper routine to wait for success response and nothing else
15221 +libssh2_publickey_response_success(LIBSSH2_PUBLICKEY * pkey)
15223 + LIBSSH2_SESSION *session = pkey->channel->session;
15224 + unsigned char *data, *s;
15225 + unsigned long data_len;
15230 + rc = libssh2_publickey_packet_receive(pkey, &data, &data_len);
15231 + if (rc == PACKET_EAGAIN) {
15232 + return PACKET_EAGAIN;
15234 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
15235 + "Timeout waiting for response from publickey subsystem",
15241 + if ((response = libssh2_publickey_response_id(&s, data_len)) < 0) {
15242 + libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
15243 + "Invalid publickey subsystem response code", 0);
15244 + LIBSSH2_FREE(session, data);
15248 + switch (response) {
15249 + case LIBSSH2_PUBLICKEY_RESPONSE_STATUS:
15250 + /* Error, or processing complete */
15252 + unsigned long status, descr_len, lang_len;
15253 + unsigned char *descr, *lang;
15255 + status = libssh2_ntohu32(s);
15257 + descr_len = libssh2_ntohu32(s);
15261 + lang_len = libssh2_ntohu32(s);
15266 + if (s > data + data_len) {
15267 + libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
15268 + "Malformed publickey subsystem packet", 0);
15269 + LIBSSH2_FREE(session, data);
15273 + if (status == LIBSSH2_PUBLICKEY_SUCCESS) {
15274 + LIBSSH2_FREE(session, data);
15278 + libssh2_publickey_status_error(pkey, session, status, descr,
15280 + LIBSSH2_FREE(session, data);
15284 + /* Unknown/Unexpected */
15285 + libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
15286 + "Unexpected publickey subsystem response, ignoring",
15288 + LIBSSH2_FREE(session, data);
15292 + /* never reached, but include `return` to silence compiler warnings */
15299 +/* *****************
15300 + * Publickey API *
15301 + ***************** */
15303 +/* {{{ libssh2_publickey_init
15304 + * Startup the publickey subsystem
15306 +LIBSSH2_API LIBSSH2_PUBLICKEY *
15307 +libssh2_publickey_init(LIBSSH2_SESSION * session)
15309 + /* 19 = packet_len(4) + version_len(4) + "version"(7) + version_num(4) */
15310 + unsigned char buffer[19];
15311 + unsigned char *s;
15315 + if (session->pkeyInit_state == libssh2_NB_state_idle) {
15316 + session->pkeyInit_data = NULL;
15317 + session->pkeyInit_pkey = NULL;
15318 + session->pkeyInit_channel = NULL;
15320 + _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY,
15321 + "Initializing publickey subsystem");
15323 + session->pkeyInit_state = libssh2_NB_state_allocated;
15326 + if (session->pkeyInit_state == libssh2_NB_state_allocated) {
15328 + session->pkeyInit_channel =
15329 + libssh2_channel_open_ex(session, "session",
15330 + sizeof("session") - 1,
15331 + LIBSSH2_CHANNEL_WINDOW_DEFAULT,
15332 + LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL,
15334 + if (!session->pkeyInit_channel
15335 + && (libssh2_session_last_errno(session) ==
15336 + LIBSSH2_ERROR_EAGAIN)) {
15337 + /* The error state is already set, so leave it */
15338 + libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
15339 + "Would block to startup channel", 0);
15341 + } else if (!session->pkeyInit_channel
15342 + && (libssh2_session_last_errno(session) !=
15343 + LIBSSH2_ERROR_EAGAIN)) {
15344 + libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE,
15345 + "Unable to startup channel", 0);
15348 + } while (!session->pkeyInit_channel);
15350 + session->pkeyInit_state = libssh2_NB_state_sent;
15353 + if (session->pkeyInit_state == libssh2_NB_state_sent) {
15354 + rc = libssh2_channel_process_startup(session->pkeyInit_channel,
15356 + sizeof("subsystem") - 1,
15357 + "publickey", strlen("publickey"));
15358 + if (rc == PACKET_EAGAIN) {
15359 + libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
15360 + "Would block starting publickey subsystem", 0);
15363 + libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE,
15364 + "Unable to request publickey subsystem", 0);
15368 + session->pkeyInit_state = libssh2_NB_state_sent1;
15371 + if (session->pkeyInit_state == libssh2_NB_state_sent1) {
15372 + rc = libssh2_channel_handle_extended_data2(session->pkeyInit_channel,
15373 + LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE);
15374 + if (rc == PACKET_EAGAIN) {
15375 + libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
15376 + "Would block starting publickey subsystem", 0);
15380 + session->pkeyInit_pkey =
15381 + LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PUBLICKEY));
15382 + if (!session->pkeyInit_pkey) {
15383 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
15384 + "Unable to allocate a new publickey structure", 0);
15387 + memset(session->pkeyInit_pkey, 0, sizeof(LIBSSH2_PUBLICKEY));
15388 + session->pkeyInit_pkey->channel = session->pkeyInit_channel;
15389 + session->pkeyInit_pkey->version = 0;
15392 + libssh2_htonu32(s, 4 + (sizeof("version") - 1) + 4);
15394 + libssh2_htonu32(s, sizeof("version") - 1);
15396 + memcpy(s, "version", sizeof("version") - 1);
15397 + s += sizeof("version") - 1;
15398 + libssh2_htonu32(s, LIBSSH2_PUBLICKEY_VERSION);
15401 + _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY,
15402 + "Sending publickey version packet advertising version %d support",
15403 + (int) LIBSSH2_PUBLICKEY_VERSION);
15405 + session->pkeyInit_state = libssh2_NB_state_sent2;
15408 + if (session->pkeyInit_state == libssh2_NB_state_sent2) {
15409 + rc = libssh2_channel_write_ex(session->pkeyInit_channel, 0,
15410 + (char *) buffer, (s - buffer));
15411 + if (rc == PACKET_EAGAIN) {
15412 + libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
15413 + "Would block sending publickey version packet", 0);
15415 + } else if ((s - buffer) != rc) {
15416 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
15417 + "Unable to send publickey version packet", 0);
15421 + session->pkeyInit_state = libssh2_NB_state_sent3;
15424 + if (session->pkeyInit_state == libssh2_NB_state_sent3) {
15426 + rc = libssh2_publickey_packet_receive(session->pkeyInit_pkey,
15427 + &session->pkeyInit_data,
15428 + &session->pkeyInit_data_len);
15429 + if (rc == PACKET_EAGAIN) {
15430 + libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
15431 + "Would block waiting for response from publickey subsystem",
15435 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
15436 + "Timeout waiting for response from publickey subsystem",
15441 + s = session->pkeyInit_data;
15443 + libssh2_publickey_response_id(&s,
15444 + session->pkeyInit_data_len)) <
15446 + libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
15447 + "Invalid publickey subsystem response code", 0);
15451 + switch (response) {
15452 + case LIBSSH2_PUBLICKEY_RESPONSE_STATUS:
15455 + unsigned long status, descr_len, lang_len;
15456 + unsigned char *descr, *lang;
15458 + status = libssh2_ntohu32(s);
15460 + descr_len = libssh2_ntohu32(s);
15464 + lang_len = libssh2_ntohu32(s);
15470 + session->pkeyInit_data + session->pkeyInit_data_len) {
15471 + libssh2_error(session,
15472 + LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
15473 + "Malformed publickey subsystem packet",
15478 + libssh2_publickey_status_error(NULL, session, status,
15479 + descr, descr_len);
15483 + case LIBSSH2_PUBLICKEY_RESPONSE_VERSION:
15484 + /* What we want */
15485 + session->pkeyInit_pkey->version = libssh2_ntohu32(s);
15486 + if (session->pkeyInit_pkey->version >
15487 + LIBSSH2_PUBLICKEY_VERSION) {
15488 + _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY,
15489 + "Truncating remote publickey version from %lu",
15490 + session->pkeyInit_pkey->version);
15491 + session->pkeyInit_pkey->version =
15492 + LIBSSH2_PUBLICKEY_VERSION;
15494 + _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY,
15495 + "Enabling publickey subsystem version %lu",
15496 + session->pkeyInit_pkey->version);
15497 + LIBSSH2_FREE(session, session->pkeyInit_data);
15498 + session->pkeyInit_data = NULL;
15499 + session->pkeyInit_state = libssh2_NB_state_idle;
15500 + return session->pkeyInit_pkey;
15503 + /* Unknown/Unexpected */
15504 + libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
15505 + "Unexpected publickey subsystem response, ignoring",
15507 + LIBSSH2_FREE(session, session->pkeyInit_data);
15508 + session->pkeyInit_data = NULL;
15513 + /* Never reached except by direct goto */
15515 + session->pkeyInit_state = libssh2_NB_state_sent4;
15516 + if (session->pkeyInit_channel) {
15517 + rc = libssh2_channel_close(session->pkeyInit_channel);
15518 + if (rc == PACKET_EAGAIN) {
15519 + libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
15520 + "Would block closing channel", 0);
15524 + if (session->pkeyInit_pkey) {
15525 + LIBSSH2_FREE(session, session->pkeyInit_pkey);
15526 + session->pkeyInit_pkey = NULL;
15528 + if (session->pkeyInit_data) {
15529 + LIBSSH2_FREE(session, session->pkeyInit_data);
15530 + session->pkeyInit_data = NULL;
15532 + session->pkeyInit_state = libssh2_NB_state_idle;
15538 +/* {{{ libssh2_publickey_add_ex
15539 + * Add a new public key entry
15542 +libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY * pkey, const unsigned char *name,
15543 + unsigned long name_len, const unsigned char *blob,
15544 + unsigned long blob_len, char overwrite,
15545 + unsigned long num_attrs,
15546 + const libssh2_publickey_attribute attrs[])
15548 + LIBSSH2_CHANNEL *channel = pkey->channel;
15549 + LIBSSH2_SESSION *session = channel->session;
15550 + /* 19 = packet_len(4) + add_len(4) + "add"(3) + name_len(4) + {name} blob_len(4) + {blob} */
15551 + unsigned long i, packet_len = 19 + name_len + blob_len;
15552 + unsigned char *comment = NULL;
15553 + unsigned long comment_len = 0;
15556 + if (pkey->add_state == libssh2_NB_state_idle) {
15557 + pkey->add_packet = NULL;
15559 + _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Adding %s publickey",
15562 + if (pkey->version == 1) {
15563 + for(i = 0; i < num_attrs; i++) {
15564 + /* Search for a comment attribute */
15565 + if (attrs[i].name_len == (sizeof("comment") - 1) &&
15566 + strncmp(attrs[i].name, "comment",
15567 + sizeof("comment") - 1) == 0) {
15568 + comment = (unsigned char *) attrs[i].value;
15569 + comment_len = attrs[i].value_len;
15573 + packet_len += 4 + comment_len;
15575 + packet_len += 5; /* overwrite(1) + attribute_count(4) */
15576 + for(i = 0; i < num_attrs; i++) {
15577 + packet_len += 9 + attrs[i].name_len + attrs[i].value_len;
15578 + /* name_len(4) + value_len(4) + mandatory(1) */
15582 + pkey->add_packet = LIBSSH2_ALLOC(session, packet_len);
15583 + if (!pkey->add_packet) {
15584 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
15585 + "Unable to allocate memory for publickey \"add\" packet",
15590 + pkey->add_s = pkey->add_packet;
15591 + libssh2_htonu32(pkey->add_s, packet_len - 4);
15592 + pkey->add_s += 4;
15593 + libssh2_htonu32(pkey->add_s, sizeof("add") - 1);
15594 + pkey->add_s += 4;
15595 + memcpy(pkey->add_s, "add", sizeof("add") - 1);
15596 + pkey->add_s += sizeof("add") - 1;
15597 + if (pkey->version == 1) {
15598 + libssh2_htonu32(pkey->add_s, comment_len);
15599 + pkey->add_s += 4;
15601 + memcpy(pkey->add_s, comment, comment_len);
15602 + pkey->add_s += comment_len;
15605 + libssh2_htonu32(pkey->add_s, name_len);
15606 + pkey->add_s += 4;
15607 + memcpy(pkey->add_s, name, name_len);
15608 + pkey->add_s += name_len;
15609 + libssh2_htonu32(pkey->add_s, blob_len);
15610 + pkey->add_s += 4;
15611 + memcpy(pkey->add_s, blob, blob_len);
15612 + pkey->add_s += blob_len;
15614 + /* Version == 2 */
15616 + libssh2_htonu32(pkey->add_s, name_len);
15617 + pkey->add_s += 4;
15618 + memcpy(pkey->add_s, name, name_len);
15619 + pkey->add_s += name_len;
15620 + libssh2_htonu32(pkey->add_s, blob_len);
15621 + pkey->add_s += 4;
15622 + memcpy(pkey->add_s, blob, blob_len);
15623 + pkey->add_s += blob_len;
15624 + *(pkey->add_s++) = overwrite ? 0x01 : 0;
15625 + libssh2_htonu32(pkey->add_s, num_attrs);
15626 + pkey->add_s += 4;
15627 + for(i = 0; i < num_attrs; i++) {
15628 + libssh2_htonu32(pkey->add_s, attrs[i].name_len);
15629 + pkey->add_s += 4;
15630 + memcpy(pkey->add_s, attrs[i].name, attrs[i].name_len);
15631 + pkey->add_s += attrs[i].name_len;
15632 + libssh2_htonu32(pkey->add_s, attrs[i].value_len);
15633 + pkey->add_s += 4;
15634 + memcpy(pkey->add_s, attrs[i].value, attrs[i].value_len);
15635 + pkey->add_s += attrs[i].value_len;
15636 + *(pkey->add_s++) = attrs[i].mandatory ? 0x01 : 0;
15640 + _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY,
15641 + "Sending publickey \"add\" packet: type=%s blob_len=%ld num_attrs=%ld",
15642 + name, blob_len, num_attrs);
15644 + pkey->add_state = libssh2_NB_state_created;
15647 + if (pkey->add_state == libssh2_NB_state_created) {
15648 + rc = libssh2_channel_write_ex(channel, 0, (char *) pkey->add_packet,
15649 + (pkey->add_s - pkey->add_packet));
15650 + if (rc == PACKET_EAGAIN) {
15651 + return PACKET_EAGAIN;
15652 + } else if ((pkey->add_s - pkey->add_packet) != rc) {
15653 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
15654 + "Unable to send publickey add packet", 0);
15655 + LIBSSH2_FREE(session, pkey->add_packet);
15656 + pkey->add_packet = NULL;
15659 + LIBSSH2_FREE(session, pkey->add_packet);
15660 + pkey->add_packet = NULL;
15662 + pkey->add_state = libssh2_NB_state_sent;
15665 + rc = libssh2_publickey_response_success(pkey);
15666 + if (rc == PACKET_EAGAIN) {
15667 + return PACKET_EAGAIN;
15670 + pkey->add_state = libssh2_NB_state_idle;
15677 +/* {{{ libssh2_publickey_remove_ex
15678 + * Remove an existing publickey so that authentication can no longer be performed using it
15681 +libssh2_publickey_remove_ex(LIBSSH2_PUBLICKEY * pkey,
15682 + const unsigned char *name, unsigned long name_len,
15683 + const unsigned char *blob, unsigned long blob_len)
15685 + LIBSSH2_CHANNEL *channel = pkey->channel;
15686 + LIBSSH2_SESSION *session = channel->session;
15687 + /* 22 = packet_len(4) + remove_len(4) + "remove"(6) + name_len(4) + {name} + blob_len(4) + {blob} */
15688 + unsigned long packet_len = 22 + name_len + blob_len;
15691 + if (pkey->remove_state == libssh2_NB_state_idle) {
15692 + pkey->remove_packet = NULL;
15694 + pkey->remove_packet = LIBSSH2_ALLOC(session, packet_len);
15695 + if (!pkey->remove_packet) {
15696 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
15697 + "Unable to allocate memory for publickey \"remove\" packet",
15702 + pkey->remove_s = pkey->remove_packet;
15703 + libssh2_htonu32(pkey->remove_s, packet_len - 4);
15704 + pkey->remove_s += 4;
15705 + libssh2_htonu32(pkey->remove_s, sizeof("remove") - 1);
15706 + pkey->remove_s += 4;
15707 + memcpy(pkey->remove_s, "remove", sizeof("remove") - 1);
15708 + pkey->remove_s += sizeof("remove") - 1;
15709 + libssh2_htonu32(pkey->remove_s, name_len);
15710 + pkey->remove_s += 4;
15711 + memcpy(pkey->remove_s, name, name_len);
15712 + pkey->remove_s += name_len;
15713 + libssh2_htonu32(pkey->remove_s, blob_len);
15714 + pkey->remove_s += 4;
15715 + memcpy(pkey->remove_s, blob, blob_len);
15716 + pkey->remove_s += blob_len;
15718 + _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY,
15719 + "Sending publickey \"remove\" packet: type=%s blob_len=%ld",
15722 + pkey->remove_state = libssh2_NB_state_created;
15725 + if (pkey->remove_state == libssh2_NB_state_created) {
15726 + rc = libssh2_channel_write_ex(channel, 0, (char *) pkey->remove_packet,
15727 + (pkey->remove_s - pkey->remove_packet));
15728 + if (rc == PACKET_EAGAIN) {
15729 + return PACKET_EAGAIN;
15730 + } else if ((pkey->remove_s - pkey->remove_packet) != rc) {
15731 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
15732 + "Unable to send publickey remove packet", 0);
15733 + LIBSSH2_FREE(session, pkey->remove_packet);
15734 + pkey->remove_packet = NULL;
15735 + pkey->remove_state = libssh2_NB_state_idle;
15738 + LIBSSH2_FREE(session, pkey->remove_packet);
15739 + pkey->remove_packet = NULL;
15741 + pkey->remove_state = libssh2_NB_state_sent;
15744 + rc = libssh2_publickey_response_success(pkey);
15745 + if (rc == PACKET_EAGAIN) {
15746 + return PACKET_EAGAIN;
15749 + pkey->remove_state = libssh2_NB_state_idle;
15756 +/* {{{ libssh2_publickey_list_fetch
15757 + * Fetch a list of supported public key from a server
15760 +libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY * pkey, unsigned long *num_keys,
15761 + libssh2_publickey_list ** pkey_list)
15763 + LIBSSH2_CHANNEL *channel = pkey->channel;
15764 + LIBSSH2_SESSION *session = channel->session;
15765 + libssh2_publickey_list *list = NULL;
15766 + unsigned long buffer_len = 12, keys = 0, max_keys = 0, i;
15767 + /* 12 = packet_len(4) + list_len(4) + "list"(4) */
15771 + if (pkey->listFetch_state == libssh2_NB_state_idle) {
15772 + pkey->listFetch_data = NULL;
15774 + pkey->listFetch_s = pkey->listFetch_buffer;
15775 + libssh2_htonu32(pkey->listFetch_s, buffer_len - 4);
15776 + pkey->listFetch_s += 4;
15777 + libssh2_htonu32(pkey->listFetch_s, sizeof("list") - 1);
15778 + pkey->listFetch_s += 4;
15779 + memcpy(pkey->listFetch_s, "list", sizeof("list") - 1);
15780 + pkey->listFetch_s += sizeof("list") - 1;
15782 + _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY,
15783 + "Sending publickey \"list\" packet");
15785 + pkey->listFetch_state = libssh2_NB_state_created;
15788 + if (pkey->listFetch_state == libssh2_NB_state_created) {
15789 + rc = libssh2_channel_write_ex(channel, 0,
15790 + (char *) pkey->listFetch_buffer,
15791 + (pkey->listFetch_s -
15792 + pkey->listFetch_buffer));
15793 + if (rc == PACKET_EAGAIN) {
15794 + return PACKET_EAGAIN;
15795 + } else if ((pkey->listFetch_s - pkey->listFetch_buffer) != rc) {
15796 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
15797 + "Unable to send publickey list packet", 0);
15798 + pkey->listFetch_state = libssh2_NB_state_idle;
15802 + pkey->listFetch_state = libssh2_NB_state_sent;
15806 + rc = libssh2_publickey_packet_receive(pkey, &pkey->listFetch_data,
15807 + &pkey->listFetch_data_len);
15808 + if (rc == PACKET_EAGAIN) {
15809 + return PACKET_EAGAIN;
15811 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
15812 + "Timeout waiting for response from publickey subsystem",
15817 + pkey->listFetch_s = pkey->listFetch_data;
15819 + libssh2_publickey_response_id(&pkey->listFetch_s,
15820 + pkey->listFetch_data_len)) < 0) {
15821 + libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
15822 + "Invalid publickey subsystem response code", 0);
15826 + switch (response) {
15827 + case LIBSSH2_PUBLICKEY_RESPONSE_STATUS:
15828 + /* Error, or processing complete */
15830 + unsigned long status, descr_len, lang_len;
15831 + unsigned char *descr, *lang;
15833 + status = libssh2_ntohu32(pkey->listFetch_s);
15834 + pkey->listFetch_s += 4;
15835 + descr_len = libssh2_ntohu32(pkey->listFetch_s);
15836 + pkey->listFetch_s += 4;
15837 + descr = pkey->listFetch_s;
15838 + pkey->listFetch_s += descr_len;
15839 + lang_len = libssh2_ntohu32(pkey->listFetch_s);
15840 + pkey->listFetch_s += 4;
15841 + lang = pkey->listFetch_s;
15842 + pkey->listFetch_s += lang_len;
15844 + if (pkey->listFetch_s >
15845 + pkey->listFetch_data + pkey->listFetch_data_len) {
15846 + libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
15847 + "Malformed publickey subsystem packet", 0);
15851 + if (status == LIBSSH2_PUBLICKEY_SUCCESS) {
15852 + LIBSSH2_FREE(session, pkey->listFetch_data);
15853 + pkey->listFetch_data = NULL;
15854 + *pkey_list = list;
15855 + *num_keys = keys;
15856 + pkey->listFetch_state = libssh2_NB_state_idle;
15860 + libssh2_publickey_status_error(pkey, session, status, descr,
15864 + case LIBSSH2_PUBLICKEY_RESPONSE_PUBLICKEY:
15865 + /* What we want */
15866 + if (keys >= max_keys) {
15867 + libssh2_publickey_list *newlist;
15868 + /* Grow the key list if necessary */
15871 + LIBSSH2_REALLOC(session, list,
15873 + 1) * sizeof(libssh2_publickey_list));
15875 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
15876 + "Unable to allocate memory for publickey list",
15882 + if (pkey->version == 1) {
15883 + unsigned long comment_len;
15885 + comment_len = libssh2_ntohu32(pkey->listFetch_s);
15886 + pkey->listFetch_s += 4;
15887 + if (comment_len) {
15888 + list[keys].num_attrs = 1;
15889 + list[keys].attrs =
15890 + LIBSSH2_ALLOC(session,
15891 + sizeof(libssh2_publickey_attribute));
15892 + if (!list[keys].attrs) {
15893 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
15894 + "Unable to allocate memory for publickey attributes",
15898 + list[keys].attrs[0].name = "comment";
15899 + list[keys].attrs[0].name_len = sizeof("comment") - 1;
15900 + list[keys].attrs[0].value = (char *) pkey->listFetch_s;
15901 + list[keys].attrs[0].value_len = comment_len;
15902 + list[keys].attrs[0].mandatory = 0;
15904 + pkey->listFetch_s += comment_len;
15906 + list[keys].num_attrs = 0;
15907 + list[keys].attrs = NULL;
15909 + list[keys].name_len = libssh2_ntohu32(pkey->listFetch_s);
15910 + pkey->listFetch_s += 4;
15911 + list[keys].name = pkey->listFetch_s;
15912 + pkey->listFetch_s += list[keys].name_len;
15913 + list[keys].blob_len = libssh2_ntohu32(pkey->listFetch_s);
15914 + pkey->listFetch_s += 4;
15915 + list[keys].blob = pkey->listFetch_s;
15916 + pkey->listFetch_s += list[keys].blob_len;
15918 + /* Version == 2 */
15919 + list[keys].name_len = libssh2_ntohu32(pkey->listFetch_s);
15920 + pkey->listFetch_s += 4;
15921 + list[keys].name = pkey->listFetch_s;
15922 + pkey->listFetch_s += list[keys].name_len;
15923 + list[keys].blob_len = libssh2_ntohu32(pkey->listFetch_s);
15924 + pkey->listFetch_s += 4;
15925 + list[keys].blob = pkey->listFetch_s;
15926 + pkey->listFetch_s += list[keys].blob_len;
15927 + list[keys].num_attrs = libssh2_ntohu32(pkey->listFetch_s);
15928 + pkey->listFetch_s += 4;
15929 + if (list[keys].num_attrs) {
15930 + list[keys].attrs =
15931 + LIBSSH2_ALLOC(session,
15932 + list[keys].num_attrs *
15933 + sizeof(libssh2_publickey_attribute));
15934 + if (!list[keys].attrs) {
15935 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
15936 + "Unable to allocate memory for publickey attributes",
15940 + for(i = 0; i < list[keys].num_attrs; i++) {
15941 + list[keys].attrs[i].name_len =
15942 + libssh2_ntohu32(pkey->listFetch_s);
15943 + pkey->listFetch_s += 4;
15944 + list[keys].attrs[i].name = (char *) pkey->listFetch_s;
15945 + pkey->listFetch_s += list[keys].attrs[i].name_len;
15946 + list[keys].attrs[i].value_len =
15947 + libssh2_ntohu32(pkey->listFetch_s);
15948 + pkey->listFetch_s += 4;
15949 + list[keys].attrs[i].value = (char *) pkey->listFetch_s;
15950 + pkey->listFetch_s += list[keys].attrs[i].value_len;
15951 + list[keys].attrs[i].mandatory = 0; /* actually an ignored value */
15954 + list[keys].attrs = NULL;
15957 + list[keys].packet = pkey->listFetch_data; /* To be FREEd in libssh2_publickey_list_free() */
15960 + list[keys].packet = NULL; /* Terminate the list */
15961 + pkey->listFetch_data = NULL;
15964 + /* Unknown/Unexpected */
15965 + libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
15966 + "Unexpected publickey subsystem response, ignoring",
15968 + LIBSSH2_FREE(session, pkey->listFetch_data);
15969 + pkey->listFetch_data = NULL;
15973 + /* Only reached via explicit goto */
15975 + if (pkey->listFetch_data) {
15976 + LIBSSH2_FREE(session, pkey->listFetch_data);
15977 + pkey->listFetch_data = NULL;
15980 + libssh2_publickey_list_free(pkey, list);
15982 + pkey->listFetch_state = libssh2_NB_state_idle;
15988 +/* {{{ libssh2_publickey_list_free
15989 + * Free a previously fetched list of public keys
15992 +libssh2_publickey_list_free(LIBSSH2_PUBLICKEY * pkey,
15993 + libssh2_publickey_list * pkey_list)
15995 + LIBSSH2_SESSION *session = pkey->channel->session;
15996 + libssh2_publickey_list *p = pkey_list;
15998 + while (p->packet) {
16000 + LIBSSH2_FREE(session, p->attrs);
16002 + LIBSSH2_FREE(session, p->packet);
16006 + LIBSSH2_FREE(session, pkey_list);
16011 +/* {{{ libssh2_publickey_shutdown
16012 + * Shutdown the publickey subsystem
16015 +libssh2_publickey_shutdown(LIBSSH2_PUBLICKEY * pkey)
16017 + LIBSSH2_SESSION *session = pkey->channel->session;
16020 + * Make sure all memory used in the state variables are free
16022 + if (pkey->receive_packet) {
16023 + LIBSSH2_FREE(session, pkey->receive_packet);
16024 + pkey->receive_packet = NULL;
16026 + if (pkey->add_packet) {
16027 + LIBSSH2_FREE(session, pkey->add_packet);
16028 + pkey->add_packet = NULL;
16030 + if (pkey->remove_packet) {
16031 + LIBSSH2_FREE(session, pkey->remove_packet);
16032 + pkey->remove_packet = NULL;
16034 + if (pkey->listFetch_data) {
16035 + LIBSSH2_FREE(session, pkey->listFetch_data);
16036 + pkey->listFetch_data = NULL;
16039 + if (libssh2_channel_free(pkey->channel) == PACKET_EAGAIN) {
16040 + return PACKET_EAGAIN;
16043 + LIBSSH2_FREE(session, pkey);
16049 Property changes on: libssh2/src/publickey.c
16050 ___________________________________________________________________
16051 Added: svn:mime-type
16053 Added: svn:keywords
16054 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
16055 Added: cvs2svn:cvs-rev
16057 Added: svn:eol-style
16060 Index: libssh2/src/kex.c
16061 ===================================================================
16062 --- libssh2/src/kex.c (.../tags/RELEASE_0_11_0)
16063 +++ libssh2/src/kex.c (.../trunk)
16065 +/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
16066 + * All rights reserved.
16068 + * Redistribution and use in source and binary forms,
16069 + * with or without modification, are permitted provided
16070 + * that the following conditions are met:
16072 + * Redistributions of source code must retain the above
16073 + * copyright notice, this list of conditions and the
16074 + * following disclaimer.
16076 + * Redistributions in binary form must reproduce the above
16077 + * copyright notice, this list of conditions and the following
16078 + * disclaimer in the documentation and/or other materials
16079 + * provided with the distribution.
16081 + * Neither the name of the copyright holder nor the names
16082 + * of any other contributors may be used to endorse or
16083 + * promote products derived from this software without
16084 + * specific prior written permission.
16086 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
16087 + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
16088 + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16089 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16090 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
16091 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
16092 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
16093 + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
16094 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
16095 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
16096 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
16097 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
16098 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
16099 + * OF SUCH DAMAGE.
16102 +#include "libssh2_priv.h"
16104 +/* TODO: Switch this to an inline and handle alloc() failures */
16105 +/* Helper macro called from libssh2_kex_method_diffie_hellman_group1_sha1_key_exchange */
16106 +#define LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(value, reqlen, version) \
16108 + libssh2_sha1_ctx hash; \
16109 + unsigned long len = 0; \
16110 + if (!(value)) { \
16111 + value = LIBSSH2_ALLOC(session, reqlen + SHA_DIGEST_LENGTH); \
16114 + while (len < (unsigned long)reqlen) { \
16115 + libssh2_sha1_init(&hash); \
16116 + libssh2_sha1_update(hash, exchange_state->k_value, \
16117 + exchange_state->k_value_len); \
16118 + libssh2_sha1_update(hash, exchange_state->h_sig_comp, \
16119 + SHA_DIGEST_LENGTH); \
16121 + libssh2_sha1_update(hash, value, len); \
16123 + libssh2_sha1_update(hash, (version), 1); \
16124 + libssh2_sha1_update(hash, session->session_id, \
16125 + session->session_id_len); \
16127 + libssh2_sha1_final(hash, (value) + len); \
16128 + len += SHA_DIGEST_LENGTH; \
16132 +/* {{{ libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange
16133 + * Diffie Hellman Key Exchange, Group Agnostic
16136 +libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *
16142 + packet_type_init,
16144 + packet_type_reply,
16149 + kmdhgGPsha1kex_state_t
16150 + * exchange_state)
16155 + if (exchange_state->state == libssh2_NB_state_idle) {
16156 + /* Setup initial values */
16157 + exchange_state->e_packet = NULL;
16158 + exchange_state->s_packet = NULL;
16159 + exchange_state->k_value = NULL;
16160 + exchange_state->ctx = _libssh2_bn_ctx_new();
16161 + exchange_state->x = _libssh2_bn_init(); /* Random from client */
16162 + exchange_state->e = _libssh2_bn_init(); /* g^x mod p */
16163 + exchange_state->f = _libssh2_bn_init(); /* g^(Random from server) mod p */
16164 + exchange_state->k = _libssh2_bn_init(); /* The shared secret: f^x mod p */
16166 + /* Zero the whole thing out */
16167 + memset(&exchange_state->req_state, 0, sizeof(packet_require_state_t));
16169 + /* Generate x and e */
16170 + _libssh2_bn_rand(exchange_state->x, group_order, 0, -1);
16171 + _libssh2_bn_mod_exp(exchange_state->e, g, exchange_state->x, p,
16172 + exchange_state->ctx);
16174 + /* Send KEX init */
16175 + /* packet_type(1) + String Length(4) + leading 0(1) */
16176 + exchange_state->e_packet_len =
16177 + _libssh2_bn_bytes(exchange_state->e) + 6;
16178 + if (_libssh2_bn_bits(exchange_state->e) % 8) {
16179 + /* Leading 00 not needed */
16180 + exchange_state->e_packet_len--;
16183 + exchange_state->e_packet =
16184 + LIBSSH2_ALLOC(session, exchange_state->e_packet_len);
16185 + if (!exchange_state->e_packet) {
16186 + libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Out of memory error",
16191 + exchange_state->e_packet[0] = packet_type_init;
16192 + libssh2_htonu32(exchange_state->e_packet + 1,
16193 + exchange_state->e_packet_len - 5);
16194 + if (_libssh2_bn_bits(exchange_state->e) % 8) {
16195 + _libssh2_bn_to_bin(exchange_state->e,
16196 + exchange_state->e_packet + 5);
16198 + exchange_state->e_packet[5] = 0;
16199 + _libssh2_bn_to_bin(exchange_state->e,
16200 + exchange_state->e_packet + 6);
16203 + _libssh2_debug(session, LIBSSH2_DBG_KEX, "Sending KEX packet %d",
16204 + (int) packet_type_init);
16205 + exchange_state->state = libssh2_NB_state_created;
16208 + if (exchange_state->state == libssh2_NB_state_created) {
16209 + rc = libssh2_packet_write(session, exchange_state->e_packet,
16210 + exchange_state->e_packet_len);
16211 + if (rc == PACKET_EAGAIN) {
16212 + return PACKET_EAGAIN;
16214 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
16215 + "Unable to send KEX init message", 0);
16219 + exchange_state->state = libssh2_NB_state_sent;
16222 + if (exchange_state->state == libssh2_NB_state_sent) {
16223 + if (session->burn_optimistic_kexinit) {
16224 + /* The first KEX packet to come along will be the guess initially
16225 + * sent by the server. That guess turned out to be wrong so we
16226 + * need to silently ignore it */
16229 + _libssh2_debug(session, LIBSSH2_DBG_KEX,
16230 + "Waiting for badly guessed KEX packet (to be ignored)");
16232 + libssh2_packet_burn(session, &exchange_state->burn_state);
16233 + if (burn_type == PACKET_EAGAIN) {
16234 + return PACKET_EAGAIN;
16235 + } else if (burn_type <= 0) {
16236 + /* Failed to receive a packet */
16240 + session->burn_optimistic_kexinit = 0;
16242 + _libssh2_debug(session, LIBSSH2_DBG_KEX,
16243 + "Burnt packet of type: %02x",
16244 + (unsigned int) burn_type);
16247 + exchange_state->state = libssh2_NB_state_sent1;
16250 + if (exchange_state->state == libssh2_NB_state_sent1) {
16251 + /* Wait for KEX reply */
16252 + rc = libssh2_packet_require_ex(session, packet_type_reply,
16253 + &exchange_state->s_packet,
16254 + &exchange_state->s_packet_len, 0, NULL,
16255 + 0, &exchange_state->req_state);
16256 + if (rc == PACKET_EAGAIN) {
16257 + return PACKET_EAGAIN;
16260 + libssh2_error(session, LIBSSH2_ERROR_TIMEOUT,
16261 + "Timed out waiting for KEX reply", 0);
16266 + /* Parse KEXDH_REPLY */
16267 + exchange_state->s = exchange_state->s_packet + 1;
16269 + session->server_hostkey_len = libssh2_ntohu32(exchange_state->s);
16270 + exchange_state->s += 4;
16271 + session->server_hostkey =
16272 + LIBSSH2_ALLOC(session, session->server_hostkey_len);
16273 + if (!session->server_hostkey) {
16274 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
16275 + "Unable to allocate memory for a copy of the host key",
16280 + memcpy(session->server_hostkey, exchange_state->s,
16281 + session->server_hostkey_len);
16282 + exchange_state->s += session->server_hostkey_len;
16286 + libssh2_md5_ctx fingerprint_ctx;
16288 + libssh2_md5_init(&fingerprint_ctx);
16289 + libssh2_md5_update(fingerprint_ctx, session->server_hostkey,
16290 + session->server_hostkey_len);
16291 + libssh2_md5_final(fingerprint_ctx, session->server_hostkey_md5);
16293 +#ifdef LIBSSH2DEBUG
16295 + char fingerprint[50], *fprint = fingerprint;
16297 + for(i = 0; i < 16; i++, fprint += 3) {
16298 + snprintf(fprint, 4, "%02x:", session->server_hostkey_md5[i]);
16300 + *(--fprint) = '\0';
16301 + _libssh2_debug(session, LIBSSH2_DBG_KEX,
16302 + "Server's MD5 Fingerprint: %s", fingerprint);
16304 +#endif /* LIBSSH2DEBUG */
16305 +#endif /* ! LIBSSH2_MD5 */
16308 + libssh2_sha1_ctx fingerprint_ctx;
16310 + libssh2_sha1_init(&fingerprint_ctx);
16311 + libssh2_sha1_update(fingerprint_ctx, session->server_hostkey,
16312 + session->server_hostkey_len);
16313 + libssh2_sha1_final(fingerprint_ctx, session->server_hostkey_sha1);
16315 +#ifdef LIBSSH2DEBUG
16317 + char fingerprint[64], *fprint = fingerprint;
16320 + for(i = 0; i < 20; i++, fprint += 3) {
16321 + snprintf(fprint, 4, "%02x:", session->server_hostkey_sha1[i]);
16323 + *(--fprint) = '\0';
16324 + _libssh2_debug(session, LIBSSH2_DBG_KEX,
16325 + "Server's SHA1 Fingerprint: %s", fingerprint);
16327 +#endif /* LIBSSH2DEBUG */
16329 + if (session->hostkey->
16330 + init(session, session->server_hostkey, session->server_hostkey_len,
16331 + &session->server_hostkey_abstract)) {
16332 + libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT,
16333 + "Unable to initialize hostkey importer", 0);
16338 + exchange_state->f_value_len = libssh2_ntohu32(exchange_state->s);
16339 + exchange_state->s += 4;
16340 + exchange_state->f_value = exchange_state->s;
16341 + exchange_state->s += exchange_state->f_value_len;
16342 + _libssh2_bn_from_bin(exchange_state->f, exchange_state->f_value_len,
16343 + exchange_state->f_value);
16345 + exchange_state->h_sig_len = libssh2_ntohu32(exchange_state->s);
16346 + exchange_state->s += 4;
16347 + exchange_state->h_sig = exchange_state->s;
16349 + /* Compute the shared secret */
16350 + _libssh2_bn_mod_exp(exchange_state->k, exchange_state->f,
16351 + exchange_state->x, p, exchange_state->ctx);
16352 + exchange_state->k_value_len = _libssh2_bn_bytes(exchange_state->k) + 5;
16353 + if (_libssh2_bn_bits(exchange_state->k) % 8) {
16354 + /* don't need leading 00 */
16355 + exchange_state->k_value_len--;
16357 + exchange_state->k_value =
16358 + LIBSSH2_ALLOC(session, exchange_state->k_value_len);
16359 + if (!exchange_state->k_value) {
16360 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
16361 + "Unable to allocate buffer for K", 0);
16365 + libssh2_htonu32(exchange_state->k_value,
16366 + exchange_state->k_value_len - 4);
16367 + if (_libssh2_bn_bits(exchange_state->k) % 8) {
16368 + _libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 4);
16370 + exchange_state->k_value[4] = 0;
16371 + _libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 5);
16374 + libssh2_sha1_init(&exchange_state->exchange_hash);
16375 + if (session->local.banner) {
16376 + libssh2_htonu32(exchange_state->h_sig_comp,
16377 + strlen((char *) session->local.banner) - 2);
16378 + libssh2_sha1_update(exchange_state->exchange_hash,
16379 + exchange_state->h_sig_comp, 4);
16380 + libssh2_sha1_update(exchange_state->exchange_hash,
16381 + (char *) session->local.banner,
16382 + strlen((char *) session->local.banner) - 2);
16384 + libssh2_htonu32(exchange_state->h_sig_comp,
16385 + sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1);
16386 + libssh2_sha1_update(exchange_state->exchange_hash,
16387 + exchange_state->h_sig_comp, 4);
16388 + libssh2_sha1_update(exchange_state->exchange_hash,
16389 + LIBSSH2_SSH_DEFAULT_BANNER,
16390 + sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1);
16393 + libssh2_htonu32(exchange_state->h_sig_comp,
16394 + strlen((char *) session->remote.banner));
16395 + libssh2_sha1_update(exchange_state->exchange_hash,
16396 + exchange_state->h_sig_comp, 4);
16397 + libssh2_sha1_update(exchange_state->exchange_hash,
16398 + session->remote.banner,
16399 + strlen((char *) session->remote.banner));
16401 + libssh2_htonu32(exchange_state->h_sig_comp,
16402 + session->local.kexinit_len);
16403 + libssh2_sha1_update(exchange_state->exchange_hash,
16404 + exchange_state->h_sig_comp, 4);
16405 + libssh2_sha1_update(exchange_state->exchange_hash,
16406 + session->local.kexinit,
16407 + session->local.kexinit_len);
16409 + libssh2_htonu32(exchange_state->h_sig_comp,
16410 + session->remote.kexinit_len);
16411 + libssh2_sha1_update(exchange_state->exchange_hash,
16412 + exchange_state->h_sig_comp, 4);
16413 + libssh2_sha1_update(exchange_state->exchange_hash,
16414 + session->remote.kexinit,
16415 + session->remote.kexinit_len);
16417 + libssh2_htonu32(exchange_state->h_sig_comp,
16418 + session->server_hostkey_len);
16419 + libssh2_sha1_update(exchange_state->exchange_hash,
16420 + exchange_state->h_sig_comp, 4);
16421 + libssh2_sha1_update(exchange_state->exchange_hash,
16422 + session->server_hostkey,
16423 + session->server_hostkey_len);
16425 + if (packet_type_init == SSH_MSG_KEX_DH_GEX_INIT) {
16426 + /* diffie-hellman-group-exchange hashes additional fields */
16427 +#ifdef LIBSSH2_DH_GEX_NEW
16428 + libssh2_htonu32(exchange_state->h_sig_comp,
16429 + LIBSSH2_DH_GEX_MINGROUP);
16430 + libssh2_htonu32(exchange_state->h_sig_comp + 4,
16431 + LIBSSH2_DH_GEX_OPTGROUP);
16432 + libssh2_htonu32(exchange_state->h_sig_comp + 8,
16433 + LIBSSH2_DH_GEX_MAXGROUP);
16434 + libssh2_sha1_update(exchange_state->exchange_hash,
16435 + exchange_state->h_sig_comp, 12);
16437 + libssh2_htonu32(exchange_state->h_sig_comp,
16438 + LIBSSH2_DH_GEX_OPTGROUP);
16439 + libssh2_sha1_update(exchange_state->exchange_hash,
16440 + exchange_state->h_sig_comp, 4);
16445 + libssh2_sha1_update(exchange_state->exchange_hash, midhash,
16449 + libssh2_sha1_update(exchange_state->exchange_hash,
16450 + exchange_state->e_packet + 1,
16451 + exchange_state->e_packet_len - 1);
16453 + libssh2_htonu32(exchange_state->h_sig_comp,
16454 + exchange_state->f_value_len);
16455 + libssh2_sha1_update(exchange_state->exchange_hash,
16456 + exchange_state->h_sig_comp, 4);
16457 + libssh2_sha1_update(exchange_state->exchange_hash,
16458 + exchange_state->f_value,
16459 + exchange_state->f_value_len);
16461 + libssh2_sha1_update(exchange_state->exchange_hash,
16462 + exchange_state->k_value,
16463 + exchange_state->k_value_len);
16465 + libssh2_sha1_final(exchange_state->exchange_hash,
16466 + exchange_state->h_sig_comp);
16468 + if (session->hostkey->
16469 + sig_verify(session, exchange_state->h_sig,
16470 + exchange_state->h_sig_len, exchange_state->h_sig_comp,
16471 + 20, &session->server_hostkey_abstract)) {
16472 + libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_SIGN,
16473 + "Unable to verify hostkey signature", 0);
16478 + _libssh2_debug(session, LIBSSH2_DBG_KEX, "Sending NEWKEYS message");
16479 + exchange_state->c = SSH_MSG_NEWKEYS;
16481 + exchange_state->state = libssh2_NB_state_sent2;
16484 + if (exchange_state->state == libssh2_NB_state_sent2) {
16485 + rc = libssh2_packet_write(session, &exchange_state->c, 1);
16486 + if (rc == PACKET_EAGAIN) {
16487 + return PACKET_EAGAIN;
16489 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
16490 + "Unable to send NEWKEYS message", 0);
16495 + exchange_state->state = libssh2_NB_state_sent3;
16498 + if (exchange_state->state == libssh2_NB_state_sent3) {
16499 + rc = libssh2_packet_require_ex(session, SSH_MSG_NEWKEYS,
16500 + &exchange_state->tmp,
16501 + &exchange_state->tmp_len, 0, NULL, 0,
16502 + &exchange_state->req_state);
16503 + if (rc == PACKET_EAGAIN) {
16504 + return PACKET_EAGAIN;
16506 + libssh2_error(session, LIBSSH2_ERROR_TIMEOUT,
16507 + "Timed out waiting for NEWKEYS", 0);
16511 + /* The first key exchange has been performed,
16512 + switch to active crypt/comp/mac mode */
16513 + session->state |= LIBSSH2_STATE_NEWKEYS;
16514 + _libssh2_debug(session, LIBSSH2_DBG_KEX, "Received NEWKEYS message");
16516 + /* This will actually end up being just packet_type(1)
16517 + for this packet type anyway */
16518 + LIBSSH2_FREE(session, exchange_state->tmp);
16520 + if (!session->session_id) {
16521 + session->session_id = LIBSSH2_ALLOC(session, SHA_DIGEST_LENGTH);
16522 + if (!session->session_id) {
16526 + memcpy(session->session_id, exchange_state->h_sig_comp,
16527 + SHA_DIGEST_LENGTH);
16528 + session->session_id_len = SHA_DIGEST_LENGTH;
16529 + _libssh2_debug(session, LIBSSH2_DBG_KEX, "session_id calculated");
16532 + /* Cleanup any existing cipher */
16533 + if (session->local.crypt->dtor) {
16534 + session->local.crypt->dtor(session,
16535 + &session->local.crypt_abstract);
16538 + /* Calculate IV/Secret/Key for each direction */
16539 + if (session->local.crypt->init) {
16540 + unsigned char *iv = NULL, *secret = NULL;
16541 + int free_iv = 0, free_secret = 0;
16543 + LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(iv,
16544 + session->local.crypt->
16550 + LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(secret,
16551 + session->local.crypt->
16552 + secret_len, "C");
16554 + LIBSSH2_FREE(session, iv);
16558 + if (session->local.crypt->
16559 + init(session, session->local.crypt, iv, &free_iv, secret,
16560 + &free_secret, 1, &session->local.crypt_abstract)) {
16561 + LIBSSH2_FREE(session, iv);
16562 + LIBSSH2_FREE(session, secret);
16568 + memset(iv, 0, session->local.crypt->iv_len);
16569 + LIBSSH2_FREE(session, iv);
16572 + if (free_secret) {
16573 + memset(secret, 0, session->local.crypt->secret_len);
16574 + LIBSSH2_FREE(session, secret);
16577 + _libssh2_debug(session, LIBSSH2_DBG_KEX,
16578 + "Client to Server IV and Key calculated");
16580 + if (session->remote.crypt->dtor) {
16581 + /* Cleanup any existing cipher */
16582 + session->remote.crypt->dtor(session,
16583 + &session->remote.crypt_abstract);
16586 + if (session->remote.crypt->init) {
16587 + unsigned char *iv = NULL, *secret = NULL;
16588 + int free_iv = 0, free_secret = 0;
16590 + LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(iv,
16591 + session->remote.crypt->
16597 + LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(secret,
16598 + session->remote.crypt->
16599 + secret_len, "D");
16601 + LIBSSH2_FREE(session, iv);
16605 + if (session->remote.crypt->
16606 + init(session, session->remote.crypt, iv, &free_iv, secret,
16607 + &free_secret, 0, &session->remote.crypt_abstract)) {
16608 + LIBSSH2_FREE(session, iv);
16609 + LIBSSH2_FREE(session, secret);
16615 + memset(iv, 0, session->remote.crypt->iv_len);
16616 + LIBSSH2_FREE(session, iv);
16619 + if (free_secret) {
16620 + memset(secret, 0, session->remote.crypt->secret_len);
16621 + LIBSSH2_FREE(session, secret);
16624 + _libssh2_debug(session, LIBSSH2_DBG_KEX,
16625 + "Server to Client IV and Key calculated");
16627 + if (session->local.mac->dtor) {
16628 + session->local.mac->dtor(session, &session->local.mac_abstract);
16631 + if (session->local.mac->init) {
16632 + unsigned char *key = NULL;
16633 + int free_key = 0;
16635 + LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(key,
16636 + session->local.mac->
16642 + session->local.mac->init(session, key, &free_key,
16643 + &session->local.mac_abstract);
16646 + memset(key, 0, session->local.mac->key_len);
16647 + LIBSSH2_FREE(session, key);
16650 + _libssh2_debug(session, LIBSSH2_DBG_KEX,
16651 + "Client to Server HMAC Key calculated");
16653 + if (session->remote.mac->dtor) {
16654 + session->remote.mac->dtor(session, &session->remote.mac_abstract);
16657 + if (session->remote.mac->init) {
16658 + unsigned char *key = NULL;
16659 + int free_key = 0;
16661 + LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(key,
16662 + session->remote.mac->
16668 + session->remote.mac->init(session, key, &free_key,
16669 + &session->remote.mac_abstract);
16672 + memset(key, 0, session->remote.mac->key_len);
16673 + LIBSSH2_FREE(session, key);
16676 + _libssh2_debug(session, LIBSSH2_DBG_KEX,
16677 + "Server to Client HMAC Key calculated");
16681 + _libssh2_bn_free(exchange_state->x);
16682 + exchange_state->x = NULL;
16683 + _libssh2_bn_free(exchange_state->e);
16684 + exchange_state->e = NULL;
16685 + _libssh2_bn_free(exchange_state->f);
16686 + exchange_state->f = NULL;
16687 + _libssh2_bn_free(exchange_state->k);
16688 + exchange_state->k = NULL;
16689 + _libssh2_bn_ctx_free(exchange_state->ctx);
16690 + exchange_state->ctx = NULL;
16692 + if (exchange_state->e_packet) {
16693 + LIBSSH2_FREE(session, exchange_state->e_packet);
16694 + exchange_state->e_packet = NULL;
16697 + if (exchange_state->s_packet) {
16698 + LIBSSH2_FREE(session, exchange_state->s_packet);
16699 + exchange_state->s_packet = NULL;
16702 + if (exchange_state->k_value) {
16703 + LIBSSH2_FREE(session, exchange_state->k_value);
16704 + exchange_state->k_value = NULL;
16707 + if (session->server_hostkey) {
16708 + LIBSSH2_FREE(session, session->server_hostkey);
16709 + session->server_hostkey = NULL;
16712 + exchange_state->state = libssh2_NB_state_idle;
16719 +/* {{{ libssh2_kex_method_diffie_hellman_group1_sha1_key_exchange
16720 + * Diffie-Hellman Group1 (Actually Group2) Key Exchange using SHA1
16723 +libssh2_kex_method_diffie_hellman_group1_sha1_key_exchange(LIBSSH2_SESSION *
16725 + key_exchange_state_low_t
16728 + static const unsigned char p_value[128] = {
16729 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
16730 + 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
16731 + 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
16732 + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
16733 + 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
16734 + 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
16735 + 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
16736 + 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
16737 + 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
16738 + 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
16739 + 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
16740 + 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
16741 + 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
16742 + 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
16743 + 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
16744 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
16749 + if (key_state->state == libssh2_NB_state_idle) {
16751 + key_state->p = _libssh2_bn_init(); /* SSH2 defined value (p_value) */
16752 + key_state->g = _libssh2_bn_init(); /* SSH2 defined value (2) */
16754 + /* Initialize P and G */
16755 + _libssh2_bn_set_word(key_state->g, 2);
16756 + _libssh2_bn_from_bin(key_state->p, 128, p_value);
16758 + _libssh2_debug(session, LIBSSH2_DBG_KEX,
16759 + "Initiating Diffie-Hellman Group1 Key Exchange");
16761 + key_state->state = libssh2_NB_state_created;
16765 + libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(session,
16770 + SSH_MSG_KEXDH_INIT,
16771 + SSH_MSG_KEXDH_REPLY,
16775 + if (ret == PACKET_EAGAIN) {
16776 + return PACKET_EAGAIN;
16779 + _libssh2_bn_free(key_state->p);
16780 + key_state->p = NULL;
16781 + _libssh2_bn_free(key_state->g);
16782 + key_state->g = NULL;
16783 + key_state->state = libssh2_NB_state_idle;
16790 +/* {{{ libssh2_kex_method_diffie_hellman_group14_sha1_key_exchange
16791 + * Diffie-Hellman Group14 Key Exchange using SHA1
16794 +libssh2_kex_method_diffie_hellman_group14_sha1_key_exchange(LIBSSH2_SESSION *
16796 + key_exchange_state_low_t
16799 + static const unsigned char p_value[256] = {
16800 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
16801 + 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
16802 + 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
16803 + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
16804 + 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
16805 + 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
16806 + 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
16807 + 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
16808 + 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
16809 + 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
16810 + 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
16811 + 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
16812 + 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
16813 + 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
16814 + 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
16815 + 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
16816 + 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
16817 + 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
16818 + 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
16819 + 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
16820 + 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
16821 + 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
16822 + 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
16823 + 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
16824 + 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
16825 + 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
16826 + 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
16827 + 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
16828 + 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
16829 + 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
16830 + 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68,
16831 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
16835 + if (key_state->state == libssh2_NB_state_idle) {
16836 + key_state->p = _libssh2_bn_init(); /* SSH2 defined value (p_value) */
16837 + key_state->g = _libssh2_bn_init(); /* SSH2 defined value (2) */
16840 + /* Initialize P and G */
16841 + _libssh2_bn_set_word(key_state->g, 2);
16842 + _libssh2_bn_from_bin(key_state->p, 256, p_value);
16844 + _libssh2_debug(session, LIBSSH2_DBG_KEX,
16845 + "Initiating Diffie-Hellman Group14 Key Exchange");
16847 + key_state->state = libssh2_NB_state_created;
16850 + libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(session,
16855 + SSH_MSG_KEXDH_INIT,
16856 + SSH_MSG_KEXDH_REPLY,
16860 + if (ret == PACKET_EAGAIN) {
16861 + return PACKET_EAGAIN;
16864 + key_state->state = libssh2_NB_state_idle;
16865 + _libssh2_bn_free(key_state->p);
16866 + key_state->p = NULL;
16867 + _libssh2_bn_free(key_state->g);
16868 + key_state->g = NULL;
16875 +/* {{{ libssh2_kex_method_diffie_hellman_group_exchange_sha1_key_exchange
16876 + * Diffie-Hellman Group Exchange Key Exchange using SHA1
16877 + * Negotiates random(ish) group for secret derivation
16880 + libssh2_kex_method_diffie_hellman_group_exchange_sha1_key_exchange
16881 + (LIBSSH2_SESSION * session, key_exchange_state_low_t * key_state)
16883 + unsigned char *s;
16884 + unsigned long p_len, g_len;
16888 + if (key_state->state == libssh2_NB_state_idle) {
16889 + key_state->p = _libssh2_bn_init();
16890 + key_state->g = _libssh2_bn_init();
16891 + /* Ask for a P and G pair */
16892 +#ifdef LIBSSH2_DH_GEX_NEW
16893 + key_state->request[0] = SSH_MSG_KEX_DH_GEX_REQUEST;
16894 + libssh2_htonu32(key_state->request + 1, LIBSSH2_DH_GEX_MINGROUP);
16895 + libssh2_htonu32(key_state->request + 5, LIBSSH2_DH_GEX_OPTGROUP);
16896 + libssh2_htonu32(key_state->request + 9, LIBSSH2_DH_GEX_MAXGROUP);
16897 + key_state->request_len = 13;
16898 + _libssh2_debug(session, LIBSSH2_DBG_KEX,
16899 + "Initiating Diffie-Hellman Group-Exchange (New Method)");
16901 + key_state->request[0] = SSH_MSG_KEX_DH_GEX_REQUEST_OLD;
16902 + libssh2_htonu32(key_state->request + 1, LIBSSH2_DH_GEX_OPTGROUP);
16903 + key_state->request_len = 5;
16904 + _libssh2_debug(session, LIBSSH2_DBG_KEX,
16905 + "Initiating Diffie-Hellman Group-Exchange (Old Method)");
16908 + key_state->state = libssh2_NB_state_created;
16911 + if (key_state->state == libssh2_NB_state_created) {
16912 + rc = libssh2_packet_write(session, key_state->request,
16913 + key_state->request_len);
16914 + if (rc == PACKET_EAGAIN) {
16915 + return PACKET_EAGAIN;
16917 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
16918 + "Unable to send Group Exchange Request", 0);
16920 + goto dh_gex_clean_exit;
16923 + key_state->state = libssh2_NB_state_sent;
16926 + if (key_state->state == libssh2_NB_state_sent) {
16927 + rc = libssh2_packet_require_ex(session, SSH_MSG_KEX_DH_GEX_GROUP,
16928 + &key_state->data, &key_state->data_len,
16929 + 0, NULL, 0, &key_state->req_state);
16930 + if (rc == PACKET_EAGAIN) {
16931 + return PACKET_EAGAIN;
16933 + libssh2_error(session, LIBSSH2_ERROR_TIMEOUT,
16934 + "Timeout waiting for GEX_GROUP reply", 0);
16936 + goto dh_gex_clean_exit;
16939 + key_state->state = libssh2_NB_state_sent1;
16942 + if (key_state->state == libssh2_NB_state_sent1) {
16943 + s = key_state->data + 1;
16944 + p_len = libssh2_ntohu32(s);
16946 + _libssh2_bn_from_bin(key_state->p, p_len, s);
16949 + g_len = libssh2_ntohu32(s);
16951 + _libssh2_bn_from_bin(key_state->g, g_len, s);
16955 + libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange
16956 + (session, key_state->g, key_state->p, p_len,
16957 + SSH_MSG_KEX_DH_GEX_INIT, SSH_MSG_KEX_DH_GEX_REPLY,
16958 + key_state->data + 1, key_state->data_len - 1,
16959 + &key_state->exchange_state);
16960 + if (ret == PACKET_EAGAIN) {
16961 + return PACKET_EAGAIN;
16964 + LIBSSH2_FREE(session, key_state->data);
16967 + dh_gex_clean_exit:
16968 + key_state->state = libssh2_NB_state_idle;
16969 + _libssh2_bn_free(key_state->g);
16970 + key_state->g = NULL;
16971 + _libssh2_bn_free(key_state->p);
16972 + key_state->p = NULL;
16979 +#define LIBSSH2_KEX_METHOD_FLAG_REQ_ENC_HOSTKEY 0x0001
16980 +#define LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY 0x0002
16982 +static const LIBSSH2_KEX_METHOD libssh2_kex_method_diffie_helman_group1_sha1 = {
16983 + "diffie-hellman-group1-sha1",
16984 + libssh2_kex_method_diffie_hellman_group1_sha1_key_exchange,
16985 + LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY,
16988 +static const LIBSSH2_KEX_METHOD libssh2_kex_method_diffie_helman_group14_sha1 = {
16989 + "diffie-hellman-group14-sha1",
16990 + libssh2_kex_method_diffie_hellman_group14_sha1_key_exchange,
16991 + LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY,
16994 +static const LIBSSH2_KEX_METHOD
16995 + libssh2_kex_method_diffie_helman_group_exchange_sha1 = {
16996 + "diffie-hellman-group-exchange-sha1",
16997 + libssh2_kex_method_diffie_hellman_group_exchange_sha1_key_exchange,
16998 + LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY,
17001 +static const LIBSSH2_KEX_METHOD *libssh2_kex_methods[] = {
17002 + &libssh2_kex_method_diffie_helman_group14_sha1,
17003 + &libssh2_kex_method_diffie_helman_group_exchange_sha1,
17004 + &libssh2_kex_method_diffie_helman_group1_sha1,
17008 +typedef struct _LIBSSH2_COMMON_METHOD
17010 + const char *name;
17011 +} LIBSSH2_COMMON_METHOD;
17013 +/* {{{ libssh2_kex_method_strlen
17014 + * Calculate the length of a particular method list's resulting string
17015 + * Includes SUM(strlen() of each individual method plus 1 (for coma)) - 1 (because the last coma isn't used)
17016 + * Another sign of bad coding practices gone mad. Pretend you don't see this.
17019 +libssh2_kex_method_strlen(LIBSSH2_COMMON_METHOD ** method)
17023 + if (!method || !*method) {
17027 + while (*method && (*method)->name) {
17028 + len += strlen((*method)->name) + 1;
17037 +/* {{{ libssh2_kex_method_list
17038 + * Generate formatted preference list in buf
17041 +libssh2_kex_method_list(unsigned char *buf, size_t list_strlen,
17042 + LIBSSH2_COMMON_METHOD ** method)
17044 + libssh2_htonu32(buf, list_strlen);
17047 + if (!method || !*method) {
17051 + while (*method && (*method)->name) {
17052 + int mlen = strlen((*method)->name);
17053 + memcpy(buf, (*method)->name, mlen);
17059 + return list_strlen + 4;
17064 +#define LIBSSH2_METHOD_PREFS_LEN(prefvar, defaultvar) ((prefvar) ? strlen(prefvar) : libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)(defaultvar)))
17065 +#define LIBSSH2_METHOD_PREFS_STR(buf, prefvarlen, prefvar, defaultvar) \
17067 + libssh2_htonu32((buf), (prefvarlen)); \
17069 + memcpy((buf), (prefvar), (prefvarlen)); \
17070 + buf += (prefvarlen); \
17072 + buf += libssh2_kex_method_list((buf), (prefvarlen), (LIBSSH2_COMMON_METHOD**)(defaultvar)); \
17075 +/* {{{ libssh2_kexinit
17076 + * Send SSH_MSG_KEXINIT packet
17079 +libssh2_kexinit(LIBSSH2_SESSION * session)
17081 + /* 62 = packet_type(1) + cookie(16) + first_packet_follows(1) +
17082 + reserved(4) + length longs(40) */
17083 + size_t data_len = 62;
17084 + size_t kex_len, hostkey_len = 0;
17085 + size_t crypt_cs_len, crypt_sc_len;
17086 + size_t comp_cs_len, comp_sc_len;
17087 + size_t mac_cs_len, mac_sc_len;
17088 + size_t lang_cs_len, lang_sc_len;
17089 + unsigned char *data, *s;
17092 + if (session->kexinit_state == libssh2_NB_state_idle) {
17094 + LIBSSH2_METHOD_PREFS_LEN(session->kex_prefs, libssh2_kex_methods);
17096 + LIBSSH2_METHOD_PREFS_LEN(session->hostkey_prefs,
17097 + libssh2_hostkey_methods());
17099 + LIBSSH2_METHOD_PREFS_LEN(session->local.crypt_prefs,
17100 + libssh2_crypt_methods());
17102 + LIBSSH2_METHOD_PREFS_LEN(session->remote.crypt_prefs,
17103 + libssh2_crypt_methods());
17105 + LIBSSH2_METHOD_PREFS_LEN(session->local.mac_prefs,
17106 + libssh2_mac_methods());
17108 + LIBSSH2_METHOD_PREFS_LEN(session->remote.mac_prefs,
17109 + libssh2_mac_methods());
17111 + LIBSSH2_METHOD_PREFS_LEN(session->local.comp_prefs,
17112 + libssh2_comp_methods());
17114 + LIBSSH2_METHOD_PREFS_LEN(session->remote.comp_prefs,
17115 + libssh2_comp_methods());
17117 + LIBSSH2_METHOD_PREFS_LEN(session->local.lang_prefs, NULL);
17119 + LIBSSH2_METHOD_PREFS_LEN(session->remote.lang_prefs, NULL);
17121 + data_len += kex_len + hostkey_len + crypt_cs_len + crypt_sc_len +
17122 + comp_cs_len + comp_sc_len + mac_cs_len + mac_sc_len +
17123 + lang_cs_len + lang_sc_len;
17125 + s = data = LIBSSH2_ALLOC(session, data_len);
17127 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
17128 + "Unable to allocate memory", 0);
17132 + *(s++) = SSH_MSG_KEXINIT;
17134 + libssh2_random(s, 16);
17137 + /* Ennumerating through these lists twice is probably (certainly?)
17138 + inefficient from a CPU standpoint, but it saves multiple
17139 + malloc/realloc calls */
17140 + LIBSSH2_METHOD_PREFS_STR(s, kex_len, session->kex_prefs,
17141 + libssh2_kex_methods);
17142 + LIBSSH2_METHOD_PREFS_STR(s, hostkey_len, session->hostkey_prefs,
17143 + libssh2_hostkey_methods());
17144 + LIBSSH2_METHOD_PREFS_STR(s, crypt_cs_len, session->local.crypt_prefs,
17145 + libssh2_crypt_methods());
17146 + LIBSSH2_METHOD_PREFS_STR(s, crypt_sc_len, session->remote.crypt_prefs,
17147 + libssh2_crypt_methods());
17148 + LIBSSH2_METHOD_PREFS_STR(s, mac_cs_len, session->local.mac_prefs,
17149 + libssh2_mac_methods());
17150 + LIBSSH2_METHOD_PREFS_STR(s, mac_sc_len, session->remote.mac_prefs,
17151 + libssh2_mac_methods());
17152 + LIBSSH2_METHOD_PREFS_STR(s, comp_cs_len, session->local.comp_prefs,
17153 + libssh2_comp_methods());
17154 + LIBSSH2_METHOD_PREFS_STR(s, comp_sc_len, session->remote.comp_prefs,
17155 + libssh2_comp_methods());
17156 + LIBSSH2_METHOD_PREFS_STR(s, lang_cs_len, session->local.lang_prefs,
17158 + LIBSSH2_METHOD_PREFS_STR(s, lang_sc_len, session->remote.lang_prefs,
17161 + /* No optimistic KEX packet follows */
17162 + /* Deal with optimistic packets
17163 + * session->flags |= KEXINIT_OPTIMISTIC
17164 + * session->flags |= KEXINIT_METHODSMATCH
17168 + /* Reserved == 0 */
17174 +#ifdef LIBSSH2DEBUG
17176 + /* Funnily enough, they'll all "appear" to be '\0' terminated */
17177 + unsigned char *p = data + 21; /* type(1) + cookie(16) + len(4) */
17179 + _libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent KEX: %s", p);
17180 + p += kex_len + 4;
17181 + _libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent HOSTKEY: %s", p);
17182 + p += hostkey_len + 4;
17183 + _libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent CRYPT_CS: %s", p);
17184 + p += crypt_cs_len + 4;
17185 + _libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent CRYPT_SC: %s", p);
17186 + p += crypt_sc_len + 4;
17187 + _libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent MAC_CS: %s", p);
17188 + p += mac_cs_len + 4;
17189 + _libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent MAC_SC: %s", p);
17190 + p += mac_sc_len + 4;
17191 + _libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent COMP_CS: %s", p);
17192 + p += comp_cs_len + 4;
17193 + _libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent COMP_SC: %s", p);
17194 + p += comp_sc_len + 4;
17195 + _libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent LANG_CS: %s", p);
17196 + p += lang_cs_len + 4;
17197 + _libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent LANG_SC: %s", p);
17198 + p += lang_sc_len + 4;
17200 +#endif /* LIBSSH2DEBUG */
17202 + session->kexinit_state = libssh2_NB_state_created;
17204 + data = session->kexinit_data;
17205 + data_len = session->kexinit_data_len;
17208 + if ((rc = libssh2_packet_write(session, data, data_len)) == PACKET_EAGAIN) {
17209 + session->kexinit_data = data;
17210 + session->kexinit_data_len = data_len;
17211 + return PACKET_EAGAIN;
17213 + LIBSSH2_FREE(session, data);
17214 + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
17215 + "Unable to send KEXINIT packet to remote host", 0);
17216 + session->kexinit_state = libssh2_NB_state_idle;
17220 + if (session->local.kexinit) {
17221 + LIBSSH2_FREE(session, session->local.kexinit);
17224 + session->local.kexinit = data;
17225 + session->local.kexinit_len = data_len;
17227 + session->kexinit_state = libssh2_NB_state_idle;
17234 +/* {{{ libssh2_kex_agree_instr
17235 + * Kex specific variant of strstr()
17236 + * Needle must be preceed by BOL or ',', and followed by ',' or EOL
17238 +static unsigned char *
17239 +libssh2_kex_agree_instr(unsigned char *haystack, unsigned long haystack_len,
17240 + const unsigned char *needle, unsigned long needle_len)
17242 + unsigned char *s;
17244 + /* Haystack too short to bother trying */
17245 + if (haystack_len < needle_len) {
17249 + /* Needle at start of haystack */
17250 + if ((strncmp((char *) haystack, (char *) needle, needle_len) == 0) &&
17251 + (needle_len == haystack_len || haystack[needle_len] == ',')) {
17256 + /* Search until we run out of comas or we run out of haystack,
17257 + whichever comes first */
17258 + while ((s = (unsigned char *) strchr((char *) s, ','))
17259 + && ((haystack_len - (s - haystack)) > needle_len)) {
17261 + /* Needle at X position */
17262 + if ((strncmp((char *) s, (char *) needle, needle_len) == 0) &&
17263 + (((s - haystack) + needle_len) == haystack_len
17264 + || s[needle_len] == ',')) {
17274 +/* {{{ libssh2_get_method_by_name
17276 +static const LIBSSH2_COMMON_METHOD *
17277 +libssh2_get_method_by_name(const char *name, int name_len,
17278 + const LIBSSH2_COMMON_METHOD ** methodlist)
17280 + while (*methodlist) {
17281 + if ((strlen((*methodlist)->name) == name_len) &&
17282 + (strncmp((*methodlist)->name, name, name_len) == 0)) {
17283 + return *methodlist;
17292 +/* {{{ libssh2_kex_agree_hostkey
17293 + * Agree on a Hostkey which works with this kex
17296 +libssh2_kex_agree_hostkey(LIBSSH2_SESSION * session, unsigned long kex_flags,
17297 + unsigned char *hostkey, unsigned long hostkey_len)
17299 + const LIBSSH2_HOSTKEY_METHOD **hostkeyp = libssh2_hostkey_methods();
17300 + unsigned char *s;
17302 + if (session->hostkey_prefs) {
17303 + s = (unsigned char *) session->hostkey_prefs;
17305 + while (s && *s) {
17306 + unsigned char *p = (unsigned char *) strchr((char *) s, ',');
17307 + int method_len = (p ? (p - s) : strlen((char *) s));
17308 + if (libssh2_kex_agree_instr(hostkey, hostkey_len, s, method_len)) {
17309 + const LIBSSH2_HOSTKEY_METHOD *method =
17310 + (const LIBSSH2_HOSTKEY_METHOD *)
17311 + libssh2_get_method_by_name((char *) s, method_len,
17312 + (const LIBSSH2_COMMON_METHOD **)
17316 + /* Invalid method -- Should never be reached */
17320 + /* So far so good, but does it suit our purposes? (Encrypting vs Signing) */
17321 + if (((kex_flags & LIBSSH2_KEX_METHOD_FLAG_REQ_ENC_HOSTKEY) ==
17322 + 0) || (method->encrypt)) {
17323 + /* Either this hostkey can do encryption or this kex just doesn't require it */
17324 + if (((kex_flags & LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY)
17325 + == 0) || (method->sig_verify)) {
17326 + /* Either this hostkey can do signing or this kex just doesn't require it */
17327 + session->hostkey = method;
17333 + s = p ? p + 1 : NULL;
17338 + while (hostkeyp && (*hostkeyp)->name) {
17339 + s = libssh2_kex_agree_instr(hostkey, hostkey_len,
17340 + (unsigned char *) (*hostkeyp)->name,
17341 + strlen((*hostkeyp)->name));
17343 + /* So far so good, but does it suit our purposes? (Encrypting vs Signing) */
17344 + if (((kex_flags & LIBSSH2_KEX_METHOD_FLAG_REQ_ENC_HOSTKEY) == 0) ||
17345 + ((*hostkeyp)->encrypt)) {
17346 + /* Either this hostkey can do encryption or this kex just doesn't require it */
17347 + if (((kex_flags & LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY) ==
17348 + 0) || ((*hostkeyp)->sig_verify)) {
17349 + /* Either this hostkey can do signing or this kex just doesn't require it */
17350 + session->hostkey = *hostkeyp;
17363 +/* {{{ libssh2_kex_agree_kex_hostkey
17364 + * Agree on a Key Exchange method and a hostkey encoding type
17367 +libssh2_kex_agree_kex_hostkey(LIBSSH2_SESSION * session, unsigned char *kex,
17368 + unsigned long kex_len, unsigned char *hostkey,
17369 + unsigned long hostkey_len)
17371 + const LIBSSH2_KEX_METHOD **kexp = libssh2_kex_methods;
17372 + unsigned char *s;
17374 + if (session->kex_prefs) {
17375 + s = (unsigned char *) session->kex_prefs;
17377 + while (s && *s) {
17378 + unsigned char *q, *p = (unsigned char *) strchr((char *) s, ',');
17379 + int method_len = (p ? (p - s) : strlen((char *) s));
17380 + if ((q = libssh2_kex_agree_instr(kex, kex_len, s, method_len))) {
17381 + const LIBSSH2_KEX_METHOD *method = (const LIBSSH2_KEX_METHOD *)
17382 + libssh2_get_method_by_name((char *) s, method_len,
17383 + (const LIBSSH2_COMMON_METHOD **)
17387 + /* Invalid method -- Should never be reached */
17391 + /* We've agreed on a key exchange method,
17392 + * Can we agree on a hostkey that works with this kex?
17394 + if (libssh2_kex_agree_hostkey
17395 + (session, method->flags, hostkey, hostkey_len) == 0) {
17396 + session->kex = method;
17397 + if (session->burn_optimistic_kexinit && (kex == q)) {
17398 + /* Server sent an optimistic packet,
17399 + * and client agrees with preference
17400 + * cancel burning the first KEX_INIT packet that comes in */
17401 + session->burn_optimistic_kexinit = 0;
17407 + s = p ? p + 1 : NULL;
17412 + while (*kexp && (*kexp)->name) {
17413 + s = libssh2_kex_agree_instr(kex, kex_len,
17414 + (unsigned char *) (*kexp)->name,
17415 + strlen((*kexp)->name));
17417 + /* We've agreed on a key exchange method,
17418 + * Can we agree on a hostkey that works with this kex?
17420 + if (libssh2_kex_agree_hostkey
17421 + (session, (*kexp)->flags, hostkey, hostkey_len) == 0) {
17422 + session->kex = *kexp;
17423 + if (session->burn_optimistic_kexinit && (kex == s)) {
17424 + /* Server sent an optimistic packet,
17425 + * and client agrees with preference
17426 + * cancel burning the first KEX_INIT packet that comes in */
17427 + session->burn_optimistic_kexinit = 0;
17439 +/* {{{ libssh2_kex_agree_crypt
17440 + * Agree on a cipher algo
17443 +libssh2_kex_agree_crypt(LIBSSH2_SESSION * session,
17444 + libssh2_endpoint_data * endpoint, unsigned char *crypt,
17445 + unsigned long crypt_len)
17447 + const LIBSSH2_CRYPT_METHOD **cryptp = libssh2_crypt_methods();
17448 + unsigned char *s;
17452 + if (endpoint->crypt_prefs) {
17453 + s = (unsigned char *) endpoint->crypt_prefs;
17455 + while (s && *s) {
17456 + unsigned char *p = (unsigned char *) strchr((char *) s, ',');
17457 + int method_len = (p ? (p - s) : strlen((char *) s));
17459 + if (libssh2_kex_agree_instr(crypt, crypt_len, s, method_len)) {
17460 + const LIBSSH2_CRYPT_METHOD *method =
17461 + (const LIBSSH2_CRYPT_METHOD *)
17462 + libssh2_get_method_by_name((char *) s, method_len,
17463 + (const LIBSSH2_COMMON_METHOD **)
17467 + /* Invalid method -- Should never be reached */
17471 + endpoint->crypt = method;
17475 + s = p ? p + 1 : NULL;
17480 + while (*cryptp && (*cryptp)->name) {
17481 + s = libssh2_kex_agree_instr(crypt, crypt_len,
17482 + (unsigned char *) (*cryptp)->name,
17483 + strlen((*cryptp)->name));
17485 + endpoint->crypt = *cryptp;
17496 +/* {{{ libssh2_kex_agree_mac
17497 + * Agree on a message authentication hash
17500 +libssh2_kex_agree_mac(LIBSSH2_SESSION * session,
17501 + libssh2_endpoint_data * endpoint, unsigned char *mac,
17502 + unsigned long mac_len)
17504 + const LIBSSH2_MAC_METHOD **macp = libssh2_mac_methods();
17505 + unsigned char *s;
17508 + if (endpoint->mac_prefs) {
17509 + s = (unsigned char *) endpoint->mac_prefs;
17511 + while (s && *s) {
17512 + unsigned char *p = (unsigned char *) strchr((char *) s, ',');
17513 + int method_len = (p ? (p - s) : strlen((char *) s));
17515 + if (libssh2_kex_agree_instr(mac, mac_len, s, method_len)) {
17516 + const LIBSSH2_MAC_METHOD *method = (const LIBSSH2_MAC_METHOD *)
17517 + libssh2_get_method_by_name((char *) s, method_len,
17518 + (const LIBSSH2_COMMON_METHOD **)
17522 + /* Invalid method -- Should never be reached */
17526 + endpoint->mac = method;
17530 + s = p ? p + 1 : NULL;
17535 + while (*macp && (*macp)->name) {
17536 + s = libssh2_kex_agree_instr(mac, mac_len,
17537 + (unsigned char *) (*macp)->name,
17538 + strlen((*macp)->name));
17540 + endpoint->mac = *macp;
17551 +/* {{{ libssh2_kex_agree_comp
17552 + * Agree on a compression scheme
17555 +libssh2_kex_agree_comp(LIBSSH2_SESSION * session,
17556 + libssh2_endpoint_data * endpoint, unsigned char *comp,
17557 + unsigned long comp_len)
17559 + const LIBSSH2_COMP_METHOD **compp = libssh2_comp_methods();
17560 + unsigned char *s;
17563 + if (endpoint->comp_prefs) {
17564 + s = (unsigned char *) endpoint->comp_prefs;
17566 + while (s && *s) {
17567 + unsigned char *p = (unsigned char *) strchr((char *) s, ',');
17568 + int method_len = (p ? (p - s) : strlen((char *) s));
17570 + if (libssh2_kex_agree_instr(comp, comp_len, s, method_len)) {
17571 + const LIBSSH2_COMP_METHOD *method =
17572 + (const LIBSSH2_COMP_METHOD *)
17573 + libssh2_get_method_by_name((char *) s, method_len,
17574 + (const LIBSSH2_COMMON_METHOD **)
17578 + /* Invalid method -- Should never be reached */
17582 + endpoint->comp = method;
17586 + s = p ? p + 1 : NULL;
17591 + while (*compp && (*compp)->name) {
17592 + s = libssh2_kex_agree_instr(comp, comp_len,
17593 + (unsigned char *) (*compp)->name,
17594 + strlen((*compp)->name));
17596 + endpoint->comp = *compp;
17607 +/* TODO: When in server mode we need to turn this logic on its head
17608 + * The Client gets to make the final call on "agreed methods"
17611 +/* {{{ libssh2_kex_agree_methods
17612 + * Decide which specific method to use of the methods offered by each party
17615 +libssh2_kex_agree_methods(LIBSSH2_SESSION * session, unsigned char *data,
17616 + unsigned data_len)
17618 + unsigned char *kex, *hostkey, *crypt_cs, *crypt_sc, *comp_cs, *comp_sc,
17619 + *mac_cs, *mac_sc, *lang_cs, *lang_sc;
17620 + size_t kex_len, hostkey_len, crypt_cs_len, crypt_sc_len, comp_cs_len;
17621 + size_t comp_sc_len, mac_cs_len, mac_sc_len, lang_cs_len, lang_sc_len;
17622 + unsigned char *s = data;
17624 + /* Skip packet_type, we know it already */
17627 + /* Skip cookie, don't worry, it's preserved in the kexinit field */
17630 + /* Locate each string */
17631 + kex_len = libssh2_ntohu32(s);
17633 + s += 4 + kex_len;
17634 + hostkey_len = libssh2_ntohu32(s);
17636 + s += 4 + hostkey_len;
17637 + crypt_cs_len = libssh2_ntohu32(s);
17638 + crypt_cs = s + 4;
17639 + s += 4 + crypt_cs_len;
17640 + crypt_sc_len = libssh2_ntohu32(s);
17641 + crypt_sc = s + 4;
17642 + s += 4 + crypt_sc_len;
17643 + mac_cs_len = libssh2_ntohu32(s);
17645 + s += 4 + mac_cs_len;
17646 + mac_sc_len = libssh2_ntohu32(s);
17648 + s += 4 + mac_sc_len;
17649 + comp_cs_len = libssh2_ntohu32(s);
17651 + s += 4 + comp_cs_len;
17652 + comp_sc_len = libssh2_ntohu32(s);
17654 + s += 4 + comp_sc_len;
17655 + lang_cs_len = libssh2_ntohu32(s);
17657 + s += 4 + lang_cs_len;
17658 + lang_sc_len = libssh2_ntohu32(s);
17660 + s += 4 + lang_sc_len;
17662 + /* If the server sent an optimistic packet, assume that it guessed wrong.
17663 + * If the guess is determined to be right (by libssh2_kex_agree_kex_hostkey)
17664 + * This flag will be reset to zero so that it's not ignored */
17665 + session->burn_optimistic_kexinit = *(s++);
17666 + /* Next uint32 in packet is all zeros (reserved) */
17668 + if (data_len < (unsigned) (s - data))
17669 + return -1; /* short packet */
17671 + if (libssh2_kex_agree_kex_hostkey
17672 + (session, kex, kex_len, hostkey, hostkey_len)) {
17676 + if (libssh2_kex_agree_crypt
17677 + (session, &session->local, crypt_cs, crypt_cs_len)
17678 + || libssh2_kex_agree_crypt(session, &session->remote, crypt_sc,
17683 + if (libssh2_kex_agree_mac(session, &session->local, mac_cs, mac_cs_len) ||
17684 + libssh2_kex_agree_mac(session, &session->remote, mac_sc, mac_sc_len)) {
17688 + if (libssh2_kex_agree_comp(session, &session->local, comp_cs, comp_cs_len)
17689 + || libssh2_kex_agree_comp(session, &session->remote, comp_sc,
17694 + if (libssh2_kex_agree_lang(session, &session->local, lang_cs, lang_cs_len)
17695 + || libssh2_kex_agree_lang(session, &session->remote, lang_sc,
17700 + _libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on KEX method: %s",
17701 + session->kex->name);
17702 + _libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on HOSTKEY method: %s",
17703 + session->hostkey->name);
17704 + _libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on CRYPT_CS method: %s",
17705 + session->local.crypt->name);
17706 + _libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on CRYPT_SC method: %s",
17707 + session->remote.crypt->name);
17708 + _libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on MAC_CS method: %s",
17709 + session->local.mac->name);
17710 + _libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on MAC_SC method: %s",
17711 + session->remote.mac->name);
17712 + _libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on COMP_CS method: %s",
17713 + session->local.comp->name);
17714 + _libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on COMP_SC method: %s",
17715 + session->remote.comp->name);
17716 + _libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on LANG_CS method:"); /* None yet */
17717 + _libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on LANG_SC method:"); /* None yet */
17719 + /* Initialize compression layer */
17720 + if (session->local.comp && session->local.comp->init &&
17721 + session->local.comp->init(session, 1, &session->local.comp_abstract)) {
17725 + if (session->remote.comp && session->remote.comp->init &&
17726 + session->remote.comp->init(session, 0,
17727 + &session->remote.comp_abstract)) {
17736 +/* {{{ libssh2_kex_exchange
17738 + * Returns 0 on success, non-zero on failure
17741 +libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange,
17742 + key_exchange_state_t * key_state)
17747 + session->state |= LIBSSH2_STATE_KEX_ACTIVE;
17749 + if (key_state->state == libssh2_NB_state_idle) {
17750 + /* Prevent loop in packet_add() */
17751 + session->state |= LIBSSH2_STATE_EXCHANGING_KEYS;
17753 + if (reexchange) {
17754 + session->kex = NULL;
17756 + if (session->hostkey && session->hostkey->dtor) {
17757 + session->hostkey->dtor(session,
17758 + &session->server_hostkey_abstract);
17760 + session->hostkey = NULL;
17763 + key_state->state = libssh2_NB_state_created;
17766 + if (!session->kex || !session->hostkey) {
17767 + if (key_state->state == libssh2_NB_state_created) {
17768 + /* Preserve in case of failure */
17769 + key_state->oldlocal = session->local.kexinit;
17770 + key_state->oldlocal_len = session->local.kexinit_len;
17772 + session->local.kexinit = NULL;
17774 + key_state->state = libssh2_NB_state_sent;
17777 + if (key_state->state == libssh2_NB_state_sent) {
17778 + retcode = libssh2_kexinit(session);
17779 + if (retcode == PACKET_EAGAIN) {
17780 + session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
17781 + return PACKET_EAGAIN;
17782 + } else if (retcode) {
17783 + session->local.kexinit = key_state->oldlocal;
17784 + session->local.kexinit_len = key_state->oldlocal_len;
17785 + key_state->state = libssh2_NB_state_idle;
17786 + session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
17787 + session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS;
17791 + key_state->state = libssh2_NB_state_sent1;
17794 + if (key_state->state == libssh2_NB_state_sent1) {
17796 + libssh2_packet_require_ex(session, SSH_MSG_KEXINIT,
17797 + &key_state->data,
17798 + &key_state->data_len, 0, NULL, 0,
17799 + &key_state->req_state);
17800 + if (retcode == PACKET_EAGAIN) {
17801 + session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
17802 + return PACKET_EAGAIN;
17803 + } else if (retcode) {
17804 + if (session->local.kexinit) {
17805 + LIBSSH2_FREE(session, session->local.kexinit);
17807 + session->local.kexinit = key_state->oldlocal;
17808 + session->local.kexinit_len = key_state->oldlocal_len;
17809 + key_state->state = libssh2_NB_state_idle;
17810 + session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
17811 + session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS;
17815 + if (session->remote.kexinit) {
17816 + LIBSSH2_FREE(session, session->remote.kexinit);
17818 + session->remote.kexinit = key_state->data;
17819 + session->remote.kexinit_len = key_state->data_len;
17821 + if (libssh2_kex_agree_methods
17822 + (session, key_state->data, key_state->data_len)) {
17826 + key_state->state = libssh2_NB_state_sent2;
17829 + key_state->state = libssh2_NB_state_sent2;
17833 + if (key_state->state == libssh2_NB_state_sent2) {
17835 + session->kex->exchange_keys(session,
17836 + &key_state->key_state_low);
17837 + if (retcode == PACKET_EAGAIN) {
17838 + session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
17839 + return PACKET_EAGAIN;
17840 + } else if (retcode) {
17841 + libssh2_error(session, LIBSSH2_ERROR_KEY_EXCHANGE_FAILURE,
17842 + "Unrecoverable error exchanging keys", 0);
17848 + /* Done with kexinit buffers */
17849 + if (session->local.kexinit) {
17850 + LIBSSH2_FREE(session, session->local.kexinit);
17851 + session->local.kexinit = NULL;
17853 + if (session->remote.kexinit) {
17854 + LIBSSH2_FREE(session, session->remote.kexinit);
17855 + session->remote.kexinit = NULL;
17858 + session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
17859 + session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS;
17861 + key_state->state = libssh2_NB_state_idle;
17868 +/* {{{ libssh2_session_method_pref
17869 + * Set preferred method
17872 +libssh2_session_method_pref(LIBSSH2_SESSION * session, int method_type,
17873 + const char *prefs)
17875 + char **prefvar, *s, *newprefs;
17876 + int prefs_len = strlen(prefs);
17877 + const LIBSSH2_COMMON_METHOD **mlist;
17879 + switch (method_type) {
17880 + case LIBSSH2_METHOD_KEX:
17881 + prefvar = &session->kex_prefs;
17882 + mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_kex_methods;
17885 + case LIBSSH2_METHOD_HOSTKEY:
17886 + prefvar = &session->hostkey_prefs;
17887 + mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_hostkey_methods();
17890 + case LIBSSH2_METHOD_CRYPT_CS:
17891 + prefvar = &session->local.crypt_prefs;
17892 + mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_crypt_methods();
17895 + case LIBSSH2_METHOD_CRYPT_SC:
17896 + prefvar = &session->remote.crypt_prefs;
17897 + mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_crypt_methods();
17900 + case LIBSSH2_METHOD_MAC_CS:
17901 + prefvar = &session->local.mac_prefs;
17902 + mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_mac_methods();
17905 + case LIBSSH2_METHOD_MAC_SC:
17906 + prefvar = &session->remote.mac_prefs;
17907 + mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_mac_methods();
17910 + case LIBSSH2_METHOD_COMP_CS:
17911 + prefvar = &session->local.comp_prefs;
17912 + mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_comp_methods();
17915 + case LIBSSH2_METHOD_COMP_SC:
17916 + prefvar = &session->remote.comp_prefs;
17917 + mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_comp_methods();
17920 + case LIBSSH2_METHOD_LANG_CS:
17921 + prefvar = &session->local.lang_prefs;
17925 + case LIBSSH2_METHOD_LANG_SC:
17926 + prefvar = &session->remote.lang_prefs;
17931 + libssh2_error(session, LIBSSH2_ERROR_INVAL,
17932 + "Invalid parameter specified for method_type", 0);
17936 + s = newprefs = LIBSSH2_ALLOC(session, prefs_len + 1);
17938 + libssh2_error(session, LIBSSH2_ERROR_ALLOC,
17939 + "Error allocated space for method preferences", 0);
17942 + memcpy(s, prefs, prefs_len + 1);
17944 + while (s && *s) {
17945 + char *p = strchr(s, ',');
17946 + int method_len = p ? (p - s) : (int) strlen(s);
17948 + if (!libssh2_get_method_by_name(s, method_len, mlist)) {
17949 + /* Strip out unsupported method */
17951 + memcpy(s, p + 1, strlen(s) - method_len);
17953 + if (s > newprefs) {
17961 + s = p ? (p + 1) : NULL;
17964 + if (strlen(newprefs) == 0) {
17965 + libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
17966 + "The requested method(s) are not currently supported",
17968 + LIBSSH2_FREE(session, newprefs);
17973 + LIBSSH2_FREE(session, *prefvar);
17975 + *prefvar = newprefs;
17982 Property changes on: libssh2/src/kex.c
17983 ___________________________________________________________________
17984 Added: svn:mime-type
17986 Added: svn:keywords
17987 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
17988 Added: cvs2svn:cvs-rev
17990 Added: svn:eol-style
17993 Index: libssh2/src/openssl.h
17994 ===================================================================
17995 --- libssh2/src/openssl.h (.../tags/RELEASE_0_11_0)
17996 +++ libssh2/src/openssl.h (.../trunk)
17998 +/* Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved.
17999 + * Author: Simon Josefsson
18001 + * Redistribution and use in source and binary forms,
18002 + * with or without modification, are permitted provided
18003 + * that the following conditions are met:
18005 + * Redistributions of source code must retain the above
18006 + * copyright notice, this list of conditions and the
18007 + * following disclaimer.
18009 + * Redistributions in binary form must reproduce the above
18010 + * copyright notice, this list of conditions and the following
18011 + * disclaimer in the documentation and/or other materials
18012 + * provided with the distribution.
18014 + * Neither the name of the copyright holder nor the names
18015 + * of any other contributors may be used to endorse or
18016 + * promote products derived from this software without
18017 + * specific prior written permission.
18019 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
18020 + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
18021 + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18022 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18023 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18024 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18025 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
18026 + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
18027 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
18028 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
18029 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
18030 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
18031 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
18032 + * OF SUCH DAMAGE.
18035 +#include <openssl/opensslconf.h>
18036 +#include <openssl/sha.h>
18037 +#ifndef OPENSSL_NO_MD5
18038 +#include <openssl/md5.h>
18040 +#include <openssl/evp.h>
18041 +#include <openssl/hmac.h>
18042 +#include <openssl/bn.h>
18043 +#include <openssl/pem.h>
18044 +#include <openssl/rand.h>
18046 +#ifdef OPENSSL_NO_RSA
18047 +# define LIBSSH2_RSA 0
18049 +# define LIBSSH2_RSA 1
18052 +#ifdef OPENSSL_NO_DSA
18053 +# define LIBSSH2_DSA 0
18055 +# define LIBSSH2_DSA 1
18058 +#ifdef OPENSSL_NO_MD5
18059 +# define LIBSSH2_MD5 0
18061 +# define LIBSSH2_MD5 1
18064 +#ifdef OPENSSL_NO_RIPEMD
18065 +# define LIBSSH2_HMAC_RIPEMD 0
18067 +# define LIBSSH2_HMAC_RIPEMD 1
18070 +#if OPENSSL_VERSION_NUMBER >= 0x00907000L && !defined(OPENSSL_NO_AES)
18071 +# define LIBSSH2_AES 1
18073 +# define LIBSSH2_AES 0
18076 +#ifdef OPENSSL_NO_BLOWFISH
18077 +# define LIBSSH2_BLOWFISH 0
18079 +# define LIBSSH2_BLOWFISH 1
18082 +#ifdef OPENSSL_NO_RC4
18083 +# define LIBSSH2_RC4 0
18085 +# define LIBSSH2_RC4 1
18088 +#ifdef OPENSSL_NO_CAST
18089 +# define LIBSSH2_CAST 0
18091 +# define LIBSSH2_CAST 1
18094 +#ifdef OPENSSL_NO_DES
18095 +# define LIBSSH2_3DES 0
18097 +# define LIBSSH2_3DES 1
18100 +#define libssh2_random(buf, len) \
18101 + RAND_bytes ((buf), (len))
18103 +#define libssh2_sha1_ctx SHA_CTX
18104 +#define libssh2_sha1_init(ctx) SHA1_Init(ctx)
18105 +#define libssh2_sha1_update(ctx, data, len) SHA1_Update(&(ctx), data, len)
18106 +#define libssh2_sha1_final(ctx, out) SHA1_Final(out, &(ctx))
18107 +#define libssh2_sha1(message, len, out) SHA1(message, len, out)
18109 +#define libssh2_md5_ctx MD5_CTX
18110 +#define libssh2_md5_init(ctx) MD5_Init(ctx)
18111 +#define libssh2_md5_update(ctx, data, len) MD5_Update(&(ctx), data, len)
18112 +#define libssh2_md5_final(ctx, out) MD5_Final(out, &(ctx))
18113 +#define libssh2_md5(message, len, out) MD5(message, len, out)
18115 +#define libssh2_hmac_ctx HMAC_CTX
18116 +#define libssh2_hmac_sha1_init(ctx, key, keylen) \
18117 + HMAC_Init(ctx, key, keylen, EVP_sha1())
18118 +#define libssh2_hmac_md5_init(ctx, key, keylen) \
18119 + HMAC_Init(ctx, key, keylen, EVP_md5())
18120 +#define libssh2_hmac_ripemd160_init(ctx, key, keylen) \
18121 + HMAC_Init(ctx, key, keylen, EVP_ripemd160())
18122 +#define libssh2_hmac_update(ctx, data, datalen) \
18123 + HMAC_Update(&(ctx), data, datalen)
18124 +#define libssh2_hmac_final(ctx, data) HMAC_Final(&(ctx), data, NULL)
18125 +#define libssh2_hmac_cleanup(ctx) HMAC_cleanup(ctx)
18127 +#define libssh2_crypto_init()
18129 +#define libssh2_rsa_ctx RSA
18131 +int _libssh2_rsa_new(libssh2_rsa_ctx ** rsa,
18132 + const unsigned char *edata,
18133 + unsigned long elen,
18134 + const unsigned char *ndata,
18135 + unsigned long nlen,
18136 + const unsigned char *ddata,
18137 + unsigned long dlen,
18138 + const unsigned char *pdata,
18139 + unsigned long plen,
18140 + const unsigned char *qdata,
18141 + unsigned long qlen,
18142 + const unsigned char *e1data,
18143 + unsigned long e1len,
18144 + const unsigned char *e2data,
18145 + unsigned long e2len,
18146 + const unsigned char *coeffdata, unsigned long coefflen);
18147 +int _libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa,
18148 + LIBSSH2_SESSION * session,
18149 + FILE * fp, unsigned const char *passphrase);
18150 +int _libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsa,
18151 + const unsigned char *sig,
18152 + unsigned long sig_len,
18153 + const unsigned char *m, unsigned long m_len);
18154 +int _libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session,
18155 + libssh2_rsa_ctx * rsactx,
18156 + const unsigned char *hash,
18157 + unsigned long hash_len,
18158 + unsigned char **signature,
18159 + unsigned long *signature_len);
18161 +#define _libssh2_rsa_free(rsactx) RSA_free(rsactx)
18163 +#define libssh2_dsa_ctx DSA
18165 +int _libssh2_dsa_new(libssh2_dsa_ctx ** dsa,
18166 + const unsigned char *pdata,
18167 + unsigned long plen,
18168 + const unsigned char *qdata,
18169 + unsigned long qlen,
18170 + const unsigned char *gdata,
18171 + unsigned long glen,
18172 + const unsigned char *ydata,
18173 + unsigned long ylen,
18174 + const unsigned char *x, unsigned long x_len);
18175 +int _libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa,
18176 + LIBSSH2_SESSION * session,
18177 + FILE * fp, unsigned const char *passphrase);
18178 +int _libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx,
18179 + const unsigned char *sig,
18180 + const unsigned char *m, unsigned long m_len);
18181 +int _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,
18182 + const unsigned char *hash,
18183 + unsigned long hash_len, unsigned char *sig);
18185 +#define _libssh2_dsa_free(dsactx) DSA_free(dsactx)
18187 +#define _libssh2_cipher_type(name) const EVP_CIPHER *(*name)(void)
18188 +#define _libssh2_cipher_ctx EVP_CIPHER_CTX
18190 +#define _libssh2_cipher_aes256 EVP_aes_256_cbc
18191 +#define _libssh2_cipher_aes192 EVP_aes_192_cbc
18192 +#define _libssh2_cipher_aes128 EVP_aes_128_cbc
18193 +#define _libssh2_cipher_blowfish EVP_bf_cbc
18194 +#define _libssh2_cipher_arcfour EVP_rc4
18195 +#define _libssh2_cipher_cast5 EVP_cast5_cbc
18196 +#define _libssh2_cipher_3des EVP_des_ede3_cbc
18198 +int _libssh2_cipher_init(_libssh2_cipher_ctx * h,
18199 + _libssh2_cipher_type(algo),
18200 + unsigned char *iv,
18201 + unsigned char *secret, int encrypt);
18203 +int _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx,
18204 + _libssh2_cipher_type(algo),
18205 + int encrypt, unsigned char *block);
18207 +#define _libssh2_cipher_dtor(ctx) EVP_CIPHER_CTX_cleanup(ctx)
18209 +#define _libssh2_bn BIGNUM
18210 +#define _libssh2_bn_ctx BN_CTX
18211 +#define _libssh2_bn_ctx_new() BN_CTX_new()
18212 +#define _libssh2_bn_ctx_free(bnctx) BN_CTX_free(bnctx)
18213 +#define _libssh2_bn_init() BN_new()
18214 +#define _libssh2_bn_rand(bn, bits, top, bottom) BN_rand(bn, bits, top, bottom)
18215 +#define _libssh2_bn_mod_exp(r, a, p, m, ctx) BN_mod_exp(r, a, p, m, ctx)
18216 +#define _libssh2_bn_set_word(bn, val) BN_set_word(bn, val)
18217 +#define _libssh2_bn_from_bin(bn, len, val) BN_bin2bn(val, len, bn)
18218 +#define _libssh2_bn_to_bin(bn, val) BN_bn2bin(bn, val)
18219 +#define _libssh2_bn_bytes(bn) BN_num_bytes(bn)
18220 +#define _libssh2_bn_bits(bn) BN_num_bits(bn)
18221 +#define _libssh2_bn_free(bn) BN_clear_free(bn)
18223 Property changes on: libssh2/src/openssl.h
18224 ___________________________________________________________________
18225 Added: svn:mime-type
18227 Added: svn:keywords
18228 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
18229 Added: cvs2svn:cvs-rev
18231 Added: svn:eol-style
18233 Added: svn:executable
18236 Index: libssh2/src/misc.c
18237 ===================================================================
18238 --- libssh2/src/misc.c (.../tags/RELEASE_0_11_0)
18239 +++ libssh2/src/misc.c (.../trunk)
18241 +/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
18242 + * All rights reserved.
18244 + * Redistribution and use in source and binary forms,
18245 + * with or without modification, are permitted provided
18246 + * that the following conditions are met:
18248 + * Redistributions of source code must retain the above
18249 + * copyright notice, this list of conditions and the
18250 + * following disclaimer.
18252 + * Redistributions in binary form must reproduce the above
18253 + * copyright notice, this list of conditions and the following
18254 + * disclaimer in the documentation and/or other materials
18255 + * provided with the distribution.
18257 + * Neither the name of the copyright holder nor the names
18258 + * of any other contributors may be used to endorse or
18259 + * promote products derived from this software without
18260 + * specific prior written permission.
18262 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
18263 + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
18264 + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18265 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18266 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18267 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18268 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
18269 + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
18270 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
18271 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
18272 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
18273 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
18274 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
18275 + * OF SUCH DAMAGE.
18278 +#include "libssh2_priv.h"
18279 +#ifdef HAVE_UNISTD_H
18280 +#include <unistd.h>
18283 +/* {{{ libssh2_ntohu32
18286 +libssh2_ntohu32(const unsigned char *buf)
18288 + return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
18293 +/* {{{ libssh2_ntohu64
18297 +libssh2_ntohu64(const unsigned char *buf)
18299 + unsigned long msl, lsl;
18301 + msl = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
18302 + lsl = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
18304 + return ((libssh2_uint64_t)msl <<32) | lsl;
18309 +/* {{{ libssh2_htonu32
18312 +libssh2_htonu32(unsigned char *buf, unsigned long value)
18314 + buf[0] = (value >> 24) & 0xFF;
18315 + buf[1] = (value >> 16) & 0xFF;
18316 + buf[2] = (value >> 8) & 0xFF;
18317 + buf[3] = value & 0xFF;
18322 +/* {{{ libssh2_htonu64
18325 +libssh2_htonu64(unsigned char *buf, libssh2_uint64_t value)
18327 + unsigned long msl = ((libssh2_uint64_t)value >> 32);
18329 + buf[0] = (msl >> 24) & 0xFF;
18330 + buf[1] = (msl >> 16) & 0xFF;
18331 + buf[2] = (msl >> 8) & 0xFF;
18332 + buf[3] = msl & 0xFF;
18334 + buf[4] = (value >> 24) & 0xFF;
18335 + buf[5] = (value >> 16) & 0xFF;
18336 + buf[6] = (value >> 8) & 0xFF;
18337 + buf[7] = value & 0xFF;
18342 +/* Base64 Conversion */
18345 +static const char libssh2_base64_table[] =
18346 + { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
18347 + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
18348 + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
18349 + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
18350 + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '\0'
18353 +static const char libssh2_base64_pad = '=';
18355 +static const short libssh2_base64_reverse_table[256] = {
18356 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
18357 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
18358 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
18359 + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
18360 + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
18361 + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
18362 + -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
18363 + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
18364 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
18365 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
18366 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
18367 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
18368 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
18369 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
18370 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
18371 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
18377 +/* {{{ libssh2_base64_decode
18378 + * Decode a base64 chunk and store it into a newly alloc'd buffer
18381 +libssh2_base64_decode(LIBSSH2_SESSION * session, char **data,
18382 + unsigned int *datalen, const char *src,
18383 + unsigned int src_len)
18385 + unsigned char *s, *d;
18387 + int i = 0, len = 0;
18389 + *data = LIBSSH2_ALLOC(session, (3 * src_len / 4) + 1);
18390 + d = (unsigned char *) *data;
18395 + for(s = (unsigned char *) src; ((char *) s) < (src + src_len); s++) {
18396 + if ((v = libssh2_base64_reverse_table[*s]) < 0)
18403 + d[len++] |= v >> 4;
18407 + d[len++] |= v >> 2;
18416 + if ((i % 4) == 1) {
18417 + /* Invalid -- We have a byte which belongs exclusively to a partial octet */
18418 + LIBSSH2_FREE(session, *data);
18428 +#ifdef LIBSSH2DEBUG
18430 +libssh2_trace(LIBSSH2_SESSION * session, int bitmask)
18432 + session->showmask = bitmask;
18437 +_libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, ...)
18439 + char buffer[1536];
18442 + static const char *const contexts[9] = {
18449 + "SFTP Subsystem",
18451 + "Publickey Subsystem",
18454 + if (context < 1 || context > 8) {
18457 + if (!(session->showmask & (1 << context))) {
18458 + /* no such output asked for */
18462 + len = snprintf(buffer, 1535, "[libssh2] %s: ", contexts[context]);
18464 + va_start(vargs, format);
18465 + len += vsnprintf(buffer + len, 1535 - len, format, vargs);
18466 + buffer[len] = '\n';
18468 + write(2, buffer, len + 1);
18474 +libssh2_trace(LIBSSH2_SESSION * session, int bitmask)
18482 Property changes on: libssh2/src/misc.c
18483 ___________________________________________________________________
18484 Added: svn:mime-type
18486 Added: svn:keywords
18487 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
18488 Added: cvs2svn:cvs-rev
18490 Added: svn:eol-style
18493 Index: libssh2/src/transport.c
18494 ===================================================================
18495 --- libssh2/src/transport.c (.../tags/RELEASE_0_11_0)
18496 +++ libssh2/src/transport.c (.../trunk)
18498 +/* Copyright (C) 2007 The Written Word, Inc. All rights reserved.
18499 + * Author: Daniel Stenberg <daniel@haxx.se>
18501 + * Redistribution and use in source and binary forms,
18502 + * with or without modification, are permitted provided
18503 + * that the following conditions are met:
18505 + * Redistributions of source code must retain the above
18506 + * copyright notice, this list of conditions and the
18507 + * following disclaimer.
18509 + * Redistributions in binary form must reproduce the above
18510 + * copyright notice, this list of conditions and the following
18511 + * disclaimer in the documentation and/or other materials
18512 + * provided with the distribution.
18514 + * Neither the name of the copyright holder nor the names
18515 + * of any other contributors may be used to endorse or
18516 + * promote products derived from this software without
18517 + * specific prior written permission.
18519 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
18520 + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
18521 + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18522 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18523 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18524 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18525 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
18526 + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
18527 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
18528 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
18529 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
18530 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
18531 + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
18532 + * OF SUCH DAMAGE.
18534 + * This file handles reading and writing to the SECSH transport layer. RFC4253.
18537 +#include "libssh2_priv.h"
18538 +#include <errno.h>
18539 +#include <fcntl.h>
18541 +#include <assert.h>
18543 +#define MAX_BLOCKSIZE 32 /* MUST fit biggest crypto block size we use/get */
18544 +#define MAX_MACSIZE 20 /* MUST fit biggest MAC length we support */
18546 +#ifdef LIBSSH2DEBUG
18547 +#define UNPRINTABLE_CHAR '.'
18549 +debugdump(LIBSSH2_SESSION * session,
18550 + const char *desc, unsigned char *ptr, unsigned long size)
18554 + FILE *stream = stdout;
18555 + unsigned int width = 0x10;
18557 + if (!(session->showmask & (1 << LIBSSH2_DBG_TRANS))) {
18558 + /* not asked for, bail out */
18562 + fprintf(stream, "=> %s (%d bytes)\n", desc, (int) size);
18564 + for(i = 0; i < size; i += width) {
18566 + fprintf(stream, "%04lx: ", (long)i);
18568 + /* hex not disabled, show it */
18569 + for(c = 0; c < width; c++) {
18570 + if (i + c < size)
18571 + fprintf(stream, "%02x ", ptr[i + c]);
18573 + fputs(" ", stream);
18576 + for(c = 0; (c < width) && (i + c < size); c++) {
18577 + fprintf(stream, "%c",
18578 + (ptr[i + c] >= 0x20) &&
18579 + (ptr[i + c] < 0x80) ? ptr[i + c] : UNPRINTABLE_CHAR);
18581 + fputc('\n', stream); /* newline */
18586 +#define debugdump(a,x,y,z)
18590 +/* decrypt() decrypts 'len' bytes from 'source' to 'dest'.
18592 + * returns PACKET_NONE on success and PACKET_FAIL on failure
18595 +static libssh2pack_t
18596 +decrypt(LIBSSH2_SESSION * session, unsigned char *source,
18597 + unsigned char *dest, int len)
18599 + struct transportpacket *p = &session->packet;
18600 + int blocksize = session->remote.crypt->blocksize;
18602 + /* if we get called with a len that isn't an even number of blocksizes
18603 + we risk losing those extra bytes */
18604 + assert((len % blocksize) == 0);
18606 + while (len >= blocksize) {
18607 + if (session->remote.crypt->crypt(session, source,
18608 + &session->remote.crypt_abstract)) {
18609 + libssh2_error(session, LIBSSH2_ERROR_DECRYPT,
18610 + (char *) "Error decrypting packet", 0);
18611 + LIBSSH2_FREE(session, p->payload);
18612 + return PACKET_FAIL;
18615 + /* if the crypt() function would write to a given address it
18616 + wouldn't have to memcpy() and we could avoid this memcpy()
18618 + memcpy(dest, source, blocksize);
18620 + len -= blocksize; /* less bytes left */
18621 + dest += blocksize; /* advance write pointer */
18622 + source += blocksize; /* advance read pointer */
18624 + return PACKET_NONE; /* all is fine */
18628 + * fullpacket() gets called when a full packet has been received and properly
18631 +static libssh2pack_t
18632 +fullpacket(LIBSSH2_SESSION * session, int encrypted /* 1 or 0 */ )
18634 + unsigned char macbuf[MAX_MACSIZE];
18635 + struct transportpacket *p = &session->packet;
18638 + if (session->fullpacket_state == libssh2_NB_state_idle) {
18639 + session->fullpacket_macstate = LIBSSH2_MAC_CONFIRMED;
18640 + session->fullpacket_payload_len = p->packet_length - 1;
18644 + /* Calculate MAC hash */
18645 + session->remote.mac->hash(session, macbuf, /* store hash here */
18646 + session->remote.seqno,
18649 + session->fullpacket_payload_len,
18650 + &session->remote.mac_abstract);
18652 + /* Compare the calculated hash with the MAC we just read from
18653 + * the network. The read one is at the very end of the payload
18654 + * buffer. Note that 'payload_len' here is the packet_length
18655 + * field which includes the padding but not the MAC.
18657 + if (memcmp(macbuf, p->payload + session->fullpacket_payload_len,
18658 + session->remote.mac->mac_len)) {
18659 + session->fullpacket_macstate = LIBSSH2_MAC_INVALID;
18663 + session->remote.seqno++;
18665 + /* ignore the padding */
18666 + session->fullpacket_payload_len -= p->padding_length;
18668 + /* Check for and deal with decompression */
18669 + if (session->remote.comp && strcmp(session->remote.comp->name, "none")) {
18670 + unsigned char *data;
18671 + unsigned long data_len;
18672 + int free_payload = 1;
18674 + if (session->remote.comp->comp(session, 0,
18675 + &data, &data_len,
18676 + LIBSSH2_PACKET_MAXDECOMP,
18679 + session->fullpacket_payload_len,
18680 + &session->remote.comp_abstract)) {
18681 + LIBSSH2_FREE(session, p->payload);
18682 + return PACKET_FAIL;
18685 + if (free_payload) {
18686 + LIBSSH2_FREE(session, p->payload);
18687 + p->payload = data;
18688 + session->fullpacket_payload_len = data_len;
18690 + if (data == p->payload) {
18691 + /* It's not to be freed, because the
18692 + * compression layer reused payload, So let's
18695 + session->fullpacket_payload_len = data_len;
18697 + /* No comp_method actually lets this happen,
18698 + * but let's prepare for the future */
18700 + LIBSSH2_FREE(session, p->payload);
18702 + /* We need a freeable struct otherwise the
18703 + * brigade won't know what to do with it */
18704 + p->payload = LIBSSH2_ALLOC(session, data_len);
18705 + if (!p->payload) {
18706 + libssh2_error(session, LIBSSH2_ERROR_ALLOC, (char *)
18707 + "Unable to allocate memory for copy of uncompressed data",
18709 + return PACKET_ENOMEM;
18711 + memcpy(p->payload, data, data_len);
18712 + session->fullpacket_payload_len = data_len;
18717 + session->fullpacket_packet_type = p->payload[0];
18719 + debugdump(session, "libssh2_packet_read() plain",
18720 + p->payload, session->fullpacket_payload_len);
18722 + session->fullpacket_state = libssh2_NB_state_created;
18725 + if (session->fullpacket_state == libssh2_NB_state_created) {
18726 + rc = libssh2_packet_add(session, p->payload,
18727 + session->fullpacket_payload_len,
18728 + session->fullpacket_macstate);
18729 + if (rc == PACKET_EAGAIN) {
18730 + return PACKET_EAGAIN;
18731 + } else if (rc < 0) {
18732 + return PACKET_FAIL;
18736 + session->fullpacket_state = libssh2_NB_state_idle;
18738 + return session->fullpacket_packet_type;
18742 +/* {{{ libssh2_packet_read
18743 + * Collect a packet into the input brigade
18744 + * block only controls whether or not to wait for a packet to start,
18745 + * Once a packet starts, libssh2 will block until it is complete
18747 + * Returns packet type added to input brigade (PACKET_NONE if nothing added),
18748 + * or PACKET_FAIL on failure and PACKET_EAGAIN if it couldn't process a full
18753 + * This function reads the binary stream as specified in chapter 6 of RFC4253
18754 + * "The Secure Shell (SSH) Transport Layer Protocol"
18757 +libssh2_packet_read(LIBSSH2_SESSION * session)
18759 + libssh2pack_t rc;
18760 + struct transportpacket *p = &session->packet;
18765 + unsigned char block[MAX_BLOCKSIZE];
18767 + int encrypted = 1;
18772 + * All channels, systems, subsystems, etc eventually make it down here
18773 + * when looking for more incoming data. If a key exchange is going on
18774 + * (LIBSSH2_STATE_EXCHANGING_KEYS bit is set) then the remote end
18775 + * will ONLY send key exchange related traffic. In non-blocking mode,
18776 + * there is a chance to break out of the kex_exchange function with an
18777 + * EAGAIN status, and never come back to it. If LIBSSH2_STATE_EXCHANGING_KEYS
18778 + * is active, then we must redirect to the key exchange. However,
18779 + * if kex_exchange is active (as in it is the one that calls this execution
18780 + * of packet_read, then don't redirect, as that would be an infinite loop!
18783 + if (session->state & LIBSSH2_STATE_EXCHANGING_KEYS &&
18784 + !(session->state & LIBSSH2_STATE_KEX_ACTIVE)) {
18786 + /* Whoever wants a packet won't get anything until the key re-exchange
18789 + _libssh2_debug(session, LIBSSH2_DBG_TRANS, "Redirecting into the"
18790 + " key re-exchange");
18791 + status = libssh2_kex_exchange(session, 1, &session->startup_key_state);
18792 + if (status == PACKET_EAGAIN) {
18793 + libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
18794 + "Would block exchanging encryption keys", 0);
18795 + return PACKET_EAGAIN;
18796 + } else if (status) {
18797 + libssh2_error(session, LIBSSH2_ERROR_KEX_FAILURE,
18798 + "Unable to exchange encryption keys",0);
18799 + return LIBSSH2_ERROR_KEX_FAILURE;
18804 + * =============================== NOTE ===============================
18805 + * I know this is very ugly and not a really good use of "goto", but
18806 + * this case statement would be even uglier to do it any other way
18808 + if (session->readPack_state == libssh2_NB_state_jump1) {
18809 + session->readPack_state = libssh2_NB_state_idle;
18810 + encrypted = session->readPack_encrypted;
18811 + goto libssh2_packet_read_point1;
18815 + if (session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) {
18816 + return PACKET_NONE;
18819 + if (session->state & LIBSSH2_STATE_NEWKEYS) {
18820 + blocksize = session->remote.crypt->blocksize;
18822 + encrypted = 0; /* not encrypted */
18823 + blocksize = 5; /* not strictly true, but we can use 5 here to
18824 + make the checks below work fine still */
18827 + /* read/use a whole big chunk into a temporary area stored in
18828 + the LIBSSH2_SESSION struct. We will decrypt data from that
18829 + buffer into the packet buffer so this temp one doesn't have
18830 + to be able to keep a whole SSH packet, just be large enough
18831 + so that we can read big chunks from the network layer. */
18833 + /* how much data there is remaining in the buffer to deal with
18834 + before we should read more from the network */
18835 + remainbuf = p->writeidx - p->readidx;
18837 + /* if remainbuf turns negative we have a bad internal error */
18838 + assert(remainbuf >= 0);
18840 + if (remainbuf < blocksize) {
18841 + /* If we have less than a blocksize left, it is too
18842 + little data to deal with, read more */
18845 + /* move any remainder to the start of the buffer so
18846 + that we can do a full refill */
18848 + memmove(p->buf, &p->buf[p->readidx], remainbuf);
18850 + p->writeidx = remainbuf;
18852 + /* nothing to move, just zero the indexes */
18853 + p->readidx = p->writeidx = 0;
18856 + /* now read a big chunk from the network into the temp buffer */
18858 + recv(session->socket_fd, &p->buf[remainbuf],
18859 + PACKETBUFSIZE - remainbuf,
18860 + LIBSSH2_SOCKET_RECV_FLAGS(session));
18861 + if (nread <= 0) {
18862 + /* check if this is due to EAGAIN and return the special
18863 + return code if so, error out normally otherwise */
18865 + switch (WSAGetLastError()) {
18866 + case WSAEWOULDBLOCK:
18870 + case WSAENOTSOCK:
18874 + case WSAENOTCONN:
18875 + case WSAECONNABORTED:
18876 + errno = WSAENOTCONN;
18883 +#endif /* WIN32 */
18884 + if ((nread < 0) && (errno == EAGAIN)) {
18885 + session->socket_block_directions =
18886 + LIBSSH2_SESSION_BLOCK_INBOUND;
18887 + return PACKET_EAGAIN;
18889 + return PACKET_FAIL;
18891 + debugdump(session, "libssh2_packet_read() raw",
18892 + &p->buf[remainbuf], nread);
18893 + /* advance write pointer */
18894 + p->writeidx += nread;
18896 + /* update remainbuf counter */
18897 + remainbuf = p->writeidx - p->readidx;
18900 + /* how much data to deal with from the buffer */
18901 + numbytes = remainbuf;
18903 + if (!p->total_num) {
18904 + /* No payload package area allocated yet. To know the
18905 + size of this payload, we need to decrypt the first
18906 + blocksize data. */
18908 + if (numbytes < blocksize) {
18909 + /* we can't act on anything less than blocksize, but this
18910 + check is only done for the initial block since once we have
18911 + got the start of a block we can in fact deal with fractions
18913 + return PACKET_EAGAIN;
18917 + rc = decrypt(session, &p->buf[p->readidx], block, blocksize);
18918 + if (rc != PACKET_NONE) {
18921 + /* save the first 5 bytes of the decrypted package, to be
18922 + used in the hash calculation later down. */
18923 + memcpy(p->init, &p->buf[p->readidx], 5);
18925 + /* the data is plain, just copy it verbatim to
18926 + the working block buffer */
18927 + memcpy(block, &p->buf[p->readidx], blocksize);
18930 + /* advance the read pointer */
18931 + p->readidx += blocksize;
18933 + /* we now have the initial blocksize bytes decrypted,
18934 + * and we can extract packet and padding length from it
18936 + p->packet_length = libssh2_ntohu32(block);
18937 + p->padding_length = block[4];
18939 + /* total_num is the number of bytes following the initial
18940 + (5 bytes) packet length and padding length fields */
18942 + p->packet_length - 1 +
18943 + (encrypted ? session->remote.mac->mac_len : 0);
18945 + /* RFC4253 section 6.1 Maximum Packet Length says:
18947 + * "All implementations MUST be able to process
18948 + * packets with uncompressed payload length of 32768
18949 + * bytes or less and total packet size of 35000 bytes
18950 + * or less (including length, padding length, payload,
18951 + * padding, and MAC.)."
18953 + if (p->total_num > LIBSSH2_PACKET_MAXPAYLOAD) {
18954 + return PACKET_TOOBIG;
18957 + /* Get a packet handle put data into. We get one to
18958 + hold all data, including padding and MAC. */
18959 + p->payload = LIBSSH2_ALLOC(session, p->total_num);
18960 + if (!p->payload) {
18961 + return PACKET_ENOMEM;
18963 + /* init write pointer to start of payload buffer */
18964 + p->wptr = p->payload;
18966 + if (blocksize > 5) {
18967 + /* copy the data from index 5 to the end of
18968 + the blocksize from the temporary buffer to
18969 + the start of the decrypted buffer */
18970 + memcpy(p->wptr, &block[5], blocksize - 5);
18971 + p->wptr += blocksize - 5; /* advance write pointer */
18974 + /* init the data_num field to the number of bytes of
18975 + the package read so far */
18976 + p->data_num = p->wptr - p->payload;
18978 + /* we already dealt with a blocksize worth of data */
18979 + numbytes -= blocksize;
18982 + /* how much there is left to add to the current payload
18984 + remainpack = p->total_num - p->data_num;
18986 + if (numbytes > remainpack) {
18987 + /* if we have more data in the buffer than what is going into this
18988 + particular packet, we limit this round to this packet only */
18989 + numbytes = remainpack;
18993 + /* At the end of the incoming stream, there is a MAC,
18994 + and we don't want to decrypt that since we need it
18995 + "raw". We MUST however decrypt the padding data
18996 + since it is used for the hash later on. */
18997 + int skip = session->remote.mac->mac_len;
18999 + /* if what we have plus numbytes is bigger than the
19000 + total minus the skip margin, we should lower the
19001 + amount to decrypt even more */
19002 + if ((p->data_num + numbytes) > (p->total_num - skip)) {
19003 + numdecrypt = (p->total_num - skip) - p->data_num;
19006 + numdecrypt = numbytes;
19007 + frac = numdecrypt % blocksize;
19009 + /* not an aligned amount of blocks,
19011 + numdecrypt -= frac;
19012 + /* and make it no unencrypted data
19018 + /* unencrypted data should not be decrypted at all */
19022 + /* if there are bytes to decrypt, do that */
19023 + if (numdecrypt > 0) {
19024 + /* now decrypt the lot */
19025 + rc = decrypt(session, &p->buf[p->readidx], p->wptr, numdecrypt);
19026 + if (rc != PACKET_NONE) {
19030 + /* advance the read pointer */
19031 + p->readidx += numdecrypt;
19032 + /* advance write pointer */
19033 + p->wptr += numdecrypt;
19034 + /* increse data_num */
19035 + p->data_num += numdecrypt;
19037 + /* bytes left to take care of without decryption */
19038 + numbytes -= numdecrypt;
19041 + /* if there are bytes to copy that aren't decrypted, simply
19042 + copy them as-is to the target buffer */
19043 + if (numbytes > 0) {
19044 + memcpy(p->wptr, &p->buf[p->readidx], numbytes);
19046 + /* advance the read pointer */
19047 + p->readidx += numbytes;
19048 + /* advance write pointer */
19049 + p->wptr += numbytes;
19050 + /* increse data_num */
19051 + p->data_num += numbytes;
19054 + /* now check how much data there's left to read to finish the
19055 + current packet */
19056 + remainpack = p->total_num - p->data_num;
19058 + if (!remainpack) {
19059 + /* we have a full packet */
19060 + libssh2_packet_read_point1:
19061 + rc = fullpacket(session, encrypted);
19062 + if (rc == PACKET_EAGAIN) {
19064 + if (session->packAdd_state != libssh2_NB_state_idle)
19066 + /* fullpacket only returns PACKET_EAGAIN if
19067 + * libssh2_packet_add returns PACKET_EAGAIN. If that
19068 + * returns PACKET_EAGAIN but the packAdd_state is idle,
19069 + * then the packet has been added to the brigade, but some
19070 + * immediate action that was taken based on the packet
19071 + * type (such as key re-exchange) is not yet complete.
19072 + * Clear the way for a new packet to be read in.
19074 + session->readPack_encrypted = encrypted;
19075 + session->readPack_state = libssh2_NB_state_jump1;
19078 + return PACKET_EAGAIN;
19081 + p->total_num = 0; /* no packet buffer available */
19085 + } while (1); /* loop */
19087 + return PACKET_FAIL; /* we never reach this point */
19092 +static libssh2pack_t
19093 +send_existing(LIBSSH2_SESSION * session, unsigned char *data,
19094 + unsigned long data_len, ssize_t * ret)
19098 + struct transportpacket *p = &session->packet;
19100 + if (!p->outbuf) {
19102 + return PACKET_NONE;
19105 + /* send as much as possible of the existing packet */
19106 + if ((data != p->odata) || (data_len != p->olen)) {
19107 + /* When we are about to complete the sending of a packet, it is vital
19108 + that the caller doesn't try to send a new/different packet since
19109 + we don't add this one up until the previous one has been sent. To
19110 + make the caller really notice his/hers flaw, we return error for
19112 + return PACKET_BADUSE;
19115 + *ret = 1; /* set to make our parent return */
19117 + /* number of bytes left to send */
19118 + length = p->ototal_num - p->osent;
19120 + rc = send(session->socket_fd, &p->outbuf[p->osent], length,
19121 + LIBSSH2_SOCKET_SEND_FLAGS(session));
19123 + if (rc == length) {
19124 + /* the remainder of the package was sent */
19125 + LIBSSH2_FREE(session, p->outbuf);
19126 + p->outbuf = NULL;
19127 + p->ototal_num = 0;
19128 + } else if (rc < 0) {
19129 + /* nothing was sent */
19130 + if (errno != EAGAIN) {
19131 + /* send failure! */
19132 + return PACKET_FAIL;
19134 + session->socket_block_directions = LIBSSH2_SESSION_BLOCK_OUTBOUND;
19135 + return PACKET_EAGAIN;
19138 + debugdump(session, "libssh2_packet_write send()", &p->outbuf[p->osent],
19140 + p->osent += length; /* we sent away this much data */
19142 + return PACKET_NONE;
19145 +/* {{{ libssh2_packet_write
19146 + * Send a packet, encrypting it and adding a MAC code if necessary
19147 + * Returns 0 on success, non-zero on failure.
19149 + * Returns PACKET_EAGAIN if it would block - and if it does so, you should
19150 + * call this function again as soon as it is likely that more data can be
19151 + * sent, and this function should then be called with the same argument set
19152 + * (same data pointer and same data_len) until zero or failure is returned.
19154 + * NOTE: this function does not verify that 'data_len' is less than ~35000
19155 + * which is what all implementations should support at least as packet size.
19156 + * (RFC4253 section 6.1)
19159 +libssh2_packet_write(LIBSSH2_SESSION * session, unsigned char *data,
19160 + unsigned long data_len)
19163 + (session->state & LIBSSH2_STATE_NEWKEYS) ? session->local.crypt->
19165 + int padding_length;
19166 + int packet_length;
19167 + int total_length;
19168 + int free_data = 0;
19169 +#ifdef RANDOM_PADDING
19171 + int seed = data[0]; /* FIXME: make this random */
19173 + struct transportpacket *p = &session->packet;
19177 + libssh2pack_t rc;
19178 + unsigned char *orgdata = data;
19179 + unsigned long orgdata_len = data_len;
19181 + debugdump(session, "libssh2_packet_write plain", data, data_len);
19183 + /* FIRST, check if we have a pending write to complete */
19184 + rc = send_existing(session, data, data_len, &ret);
19189 + encrypted = (session->state & LIBSSH2_STATE_NEWKEYS) ? 1 : 0;
19191 + /* check if we should compress */
19192 + if (encrypted && strcmp(session->local.comp->name, "none")) {
19193 + if (session->local.comp->comp(session, 1, &data, &data_len,
19194 + LIBSSH2_PACKET_MAXCOMP,
19195 + &free_data, data, data_len,
19196 + &session->local.comp_abstract)) {
19197 + return PACKET_COMPRESS; /* compression failure */
19201 + /* RFC4253 says: Note that the length of the concatenation of
19202 + 'packet_length', 'padding_length', 'payload', and 'random padding'
19203 + MUST be a multiple of the cipher block size or 8, whichever is
19206 + /* Plain math: (4 + 1 + packet_length + padding_length) % blocksize == 0 */
19208 + packet_length = data_len + 1 + 4; /* 1 is for padding_length field
19209 + 4 for the packet_length field */
19211 + /* at this point we have it all except the padding */
19213 + /* first figure out our minimum padding amount to make it an even
19215 + padding_length = blocksize - (packet_length % blocksize);
19217 + /* if the padding becomes too small we add another blocksize worth
19218 + of it (taken from the original libssh2 where it didn't have any
19219 + real explanation) */
19220 + if (padding_length < 4) {
19221 + padding_length += blocksize;
19223 +#ifdef RANDOM_PADDING
19224 + /* FIXME: we can add padding here, but that also makes the packets
19227 + /* now we can add 'blocksize' to the padding_length N number of times
19228 + (to "help thwart traffic analysis") but it must be less than 255 in
19230 + rand_max = (255 - padding_length) / blocksize + 1;
19231 + padding_length += blocksize * (seed % rand_max);
19234 + packet_length += padding_length;
19236 + /* append the MAC length to the total_length size */
19238 + packet_length + (encrypted ? session->local.mac->mac_len : 0);
19240 + /* allocate memory to store the outgoing packet in, in case we can't
19241 + send the whole one and thus need to keep it after this function
19243 + p->outbuf = LIBSSH2_ALLOC(session, total_length);
19244 + if (!p->outbuf) {
19245 + return PACKET_ENOMEM;
19248 + /* store packet_length, which is the size of the whole packet except
19249 + the MAC and the packet_length field itself */
19250 + libssh2_htonu32(p->outbuf, packet_length - 4);
19251 + /* store padding_length */
19252 + p->outbuf[4] = padding_length;
19253 + /* copy the payload data */
19254 + memcpy(p->outbuf + 5, data, data_len);
19255 + /* fill the padding area with random junk */
19256 + libssh2_random(p->outbuf + 5 + data_len, padding_length);
19258 + LIBSSH2_FREE(session, data);
19262 + /* Calculate MAC hash. Put the output at index packet_length,
19263 + since that size includes the whole packet. The MAC is
19264 + calculated on the entire unencrypted packet, including all
19265 + fields except the MAC field itself. */
19266 + session->local.mac->hash(session, p->outbuf + packet_length,
19267 + session->local.seqno, p->outbuf,
19268 + packet_length, NULL, 0,
19269 + &session->local.mac_abstract);
19271 + /* Encrypt the whole packet data, one block size at a time.
19272 + The MAC field is not encrypted. */
19273 + for(i = 0; i < packet_length; i += session->local.crypt->blocksize) {
19274 + unsigned char *ptr = &p->outbuf[i];
19275 + if (session->local.crypt->crypt(session, ptr,
19276 + &session->local.crypt_abstract))
19277 + return PACKET_FAIL; /* encryption failure */
19281 + session->local.seqno++;
19283 + ret = send(session->socket_fd, p->outbuf, total_length,
19284 + LIBSSH2_SOCKET_SEND_FLAGS(session));
19287 + debugdump(session, "libssh2_packet_write send()", p->outbuf, ret);
19289 + if (ret != total_length) {
19290 + if ((ret > 0) || ((ret == -1) && (errno == EAGAIN))) {
19291 + /* the whole packet could not be sent, save the rest */
19292 + session->socket_block_directions = LIBSSH2_SESSION_BLOCK_OUTBOUND;
19293 + p->odata = orgdata;
19294 + p->olen = orgdata_len;
19295 + p->osent = (ret == -1) ? 0 : ret;
19296 + p->ototal_num = total_length;
19297 + return PACKET_EAGAIN;
19299 + return PACKET_FAIL;
19302 + /* the whole thing got sent away */
19305 + LIBSSH2_FREE(session, p->outbuf);
19306 + p->outbuf = NULL;
19308 + return PACKET_NONE; /* all is good */
19314 Property changes on: libssh2/src/transport.c
19315 ___________________________________________________________________
19316 Added: svn:mime-type
19318 Added: svn:keywords
19319 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
19320 Added: cvs2svn:cvs-rev
19322 Added: svn:eol-style
19324 Added: svn:executable
19328 Property changes on: libssh2/src
19329 ___________________________________________________________________
19335 ===================================================================
19336 Cannot display: file marked as a binary type.
19337 svn:mime-type = application/xml
19339 Property changes on: package.xml
19340 ___________________________________________________________________
19341 Deleted: svn:mime-type
19344 Index: ssh2_fopen_wrappers.c
19345 ===================================================================
19346 --- ssh2_fopen_wrappers.c (.../tags/RELEASE_0_11_0)
19347 +++ ssh2_fopen_wrappers.c (.../trunk)
19349 libssh2_channel_set_blocking(abstract->channel, abstract->is_blocking);
19351 readstate = libssh2_channel_read_ex(abstract->channel, abstract->streamid, buf, count);
19352 - return (readstate == LIBSSH2_ERROR_EAGAIN ? 0 : readstate);
19353 + return (readstate < 0 ? 0 : readstate);
19356 static int php_ssh2_channel_stream_close(php_stream *stream, int close_handle TSRMLS_DC)
19358 Property changes on: ssh2_fopen_wrappers.c
19359 ___________________________________________________________________
19360 Modified: cvs2svn:cvs-rev
19365 ===================================================================
19366 --- php_ssh2.h (.../tags/RELEASE_0_11_0)
19367 +++ php_ssh2.h (.../trunk)
19368 @@ -101,6 +101,10 @@
19369 } php_ssh2_pkey_subsys_data;
19373 +#define closesocket(s) close(s)
19377 #define SSH2_TSRMLS_SET(datap) ((php_ssh2_session_data*)(datap))->tsrm_ls = TSRMLS_C
19378 #define SSH2_TSRMLS_FETCH(datap) TSRMLS_D = ((php_ssh2_session_data*)(datap))->tsrm_ls
19379 @@ -109,6 +113,12 @@
19380 #define SSH2_TSRMLS_FETCH(datap)
19383 +#if (PHP_MAJOR_VERSION == 5) && (PHP_MINOR_VERSION >= 3)
19384 +#define ZEND_IS_CALLABLE_TSRMLS_CC TSRMLS_CC
19386 +#define ZEND_IS_CALLABLE_TSRMLS_CC
19389 /* < 5.3 compatibility */
19390 #ifndef Z_REFCOUNT_P
19391 #define Z_REFCOUNT_P(pz) (pz)->refcount
19393 Property changes on: php_ssh2.h
19394 ___________________________________________________________________
19395 Modified: cvs2svn:cvs-rev
19399 Index: EXPERIMENTAL
19400 ===================================================================
19402 Property changes on: EXPERIMENTAL
19403 ___________________________________________________________________
19404 Added: svn:eol-style
19406 Added: svn:keywords
19407 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
19408 Added: cvs2svn:cvs-rev
19412 Property changes on: .
19413 ___________________________________________________________________
19462 scan_makefile_in.awk