]> git.pld-linux.org Git - packages/php-pecl-ssh2.git/blame - branch.diff
- php 5.5 rebuild
[packages/php-pecl-ssh2.git] / branch.diff
CommitLineData
93ebbc61
ER
1Index: config.w32
2===================================================================
3--- config.w32 (.../tags/RELEASE_0_11_0)
4+++ config.w32 (.../trunk)
5@@ -0,0 +1,37 @@
6+// $Id$
7+// vim:ft=javascript
8+
9+ARG_WITH("ssh2", "SSH2 support", "no");
10+
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)) {
17+
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");
23+
24+ ADD_FLAG('CFLAGS_SSH2', '/DLIBSSH2_WIN32=1 /DLIBSSH2_API= /I ' +
25+ configure_module_dirname + '/libssh2/include');
26+ }
27+
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);
33+
34+ EXTENSION("ssh2", "ssh2.c ssh2_fopen_wrappers.c ssh2_sftp.c");
35+
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");
39+ } else {
40+ WARNING("ssh2 not enabled: libraries or headers not found");
41+ }
42+}
43
44Property changes on: config.w32
45___________________________________________________________________
46Added: svn:eol-style
47 + native
48Added: svn:keywords
49 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
50Added: cvs2svn:cvs-rev
51 + 1.11
52
53Index: ssh2.c
54===================================================================
55--- ssh2.c (.../tags/RELEASE_0_11_0)
56+++ ssh2.c (.../trunk)
57@@ -47,14 +47,9 @@
58 int le_ssh2_pkey_subsys;
59 #endif
60
61-#ifdef ZEND_ENGINE_2
62-static
63- ZEND_BEGIN_ARG_INFO(php_ssh2_first_arg_force_ref, 0)
64- ZEND_ARG_PASS_INFO(1)
65- ZEND_END_ARG_INFO()
66-#else
67-static unsigned char php_ssh2_first_arg_force_ref[] = { 1, BYREF_FORCE };
68-#endif
69+ZEND_BEGIN_ARG_INFO(php_ssh2_first_arg_force_ref, 0)
70+ ZEND_ARG_PASS_INFO(1)
71+ZEND_END_ARG_INFO()
72
73 /* *************
74 * Callbacks *
75@@ -248,7 +243,7 @@
76 /* {{{ php_ssh2_set_callback
77 * Try to set a method if it's passed in with the hash table
78 */
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)
81 {
82 zval **handler, *copyval;
83 void *internal_handler;
84@@ -257,7 +252,7 @@
85 return 0;
86 }
87
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)) {
90 return -1;
91 }
92
93@@ -358,7 +353,7 @@
94 if (!session) {
95 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to initialize SSH2 session");
96 efree(data);
97- close(socket);
98+ closesocket(socket);
99 return NULL;
100 }
101 libssh2_banner_set(session, LIBSSH2_SSH_DEFAULT_BANNER " PHP");
102@@ -411,19 +406,19 @@
103 if (callbacks) {
104 /* ignore debug disconnect macerror */
105
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");
109 }
110
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");
114 }
115
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");
119 }
120
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");
124 }
125 }
126@@ -434,7 +429,7 @@
127
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);
130- close(socket);
131+ closesocket(socket);
132 libssh2_session_free(session);
133 efree(data);
134 return NULL;
135@@ -1148,7 +1143,7 @@
136 zval_ptr_dtor(&(*data)->disconnect_cb);
137 }
138
139- close((*data)->socket);
140+ closesocket((*data)->socket);
141
142 efree(*data);
143 *data = NULL;
144@@ -1274,7 +1269,7 @@
145
146 /* {{{ ssh2_functions[]
147 */
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)
153
154Property changes on: ssh2.c
155___________________________________________________________________
156Modified: cvs2svn:cvs-rev
157 - 1.22
158 + 1.25
159
160Index: libssh2/include/libssh2_publickey.h
161===================================================================
162--- libssh2/include/libssh2_publickey.h (.../tags/RELEASE_0_11_0)
163+++ libssh2/include/libssh2_publickey.h (.../trunk)
164@@ -0,0 +1,101 @@
165+/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
166+ * All rights reserved.
167+ *
168+ * Redistribution and use in source and binary forms,
169+ * with or without modification, are permitted provided
170+ * that the following conditions are met:
171+ *
172+ * Redistributions of source code must retain the above
173+ * copyright notice, this list of conditions and the
174+ * following disclaimer.
175+ *
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.
180+ *
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.
185+ *
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
199+ * OF SUCH DAMAGE.
200+ */
201+
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
205+ *
206+ * For more information on the publickey subsystem,
207+ * refer to IETF draft: secsh-publickey
208+ */
209+
210+#ifndef LIBSSH2_PUBLICKEY_H
211+#define LIBSSH2_PUBLICKEY_H 1
212+
213+typedef struct _LIBSSH2_PUBLICKEY LIBSSH2_PUBLICKEY;
214+
215+typedef struct _libssh2_publickey_attribute {
216+ const char *name;
217+ unsigned long name_len;
218+ const char *value;
219+ unsigned long value_len;
220+ char mandatory;
221+} libssh2_publickey_attribute;
222+
223+typedef struct _libssh2_publickey_list {
224+ unsigned char *packet; /* For freeing */
225+
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;
233+
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) },
237+
238+#ifdef __cplusplus
239+extern "C" {
240+#endif
241+
242+/* Publickey Subsystem */
243+LIBSSH2_API LIBSSH2_PUBLICKEY *libssh2_publickey_init(LIBSSH2_SESSION *session);
244+
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))
250+
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))
255+
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);
258+
259+LIBSSH2_API int libssh2_publickey_shutdown(LIBSSH2_PUBLICKEY *pkey);
260+
261+#ifdef __cplusplus
262+} /* extern "C" */
263+#endif
264+
265+#endif /* ndef: LIBSSH2_PUBLICKEY_H */
266
267Property changes on: libssh2/include/libssh2_publickey.h
268___________________________________________________________________
269Added: svn:mime-type
270 + text/x-c
271Added: svn:keywords
272 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
273Added: cvs2svn:cvs-rev
274 + 1.2
275Added: svn:eol-style
276 + native
277
278Index: libssh2/include/libssh2_sftp.h
279===================================================================
280--- libssh2/include/libssh2_sftp.h (.../tags/RELEASE_0_11_0)
281+++ libssh2/include/libssh2_sftp.h (.../trunk)
282@@ -0,0 +1,251 @@
283+/* Copyright (c) 2004-2008, Sara Golemon <sarag@libssh2.org>
284+ * All rights reserved.
285+ *
286+ * Redistribution and use in source and binary forms,
287+ * with or without modification, are permitted provided
288+ * that the following conditions are met:
289+ *
290+ * Redistributions of source code must retain the above
291+ * copyright notice, this list of conditions and the
292+ * following disclaimer.
293+ *
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.
298+ *
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.
303+ *
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
317+ * OF SUCH DAMAGE.
318+ */
319+
320+#ifndef LIBSSH2_SFTP_H
321+#define LIBSSH2_SFTP_H 1
322+
323+#ifndef WIN32
324+#include <unistd.h>
325+#endif
326+
327+#ifdef __cplusplus
328+extern "C" {
329+#endif
330+
331+/* Note: Version 6 was documented at the time of writing
332+ * However it was marked as "DO NOT IMPLEMENT" due to pending changes
333+ *
334+ * Let's start with Version 3 (The version found in OpenSSH) and go from there
335+ */
336+#define LIBSSH2_SFTP_VERSION 3
337+#define LIBSSH2_SFTP_PACKET_MAXLEN 40000
338+
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;
342+
343+/* Flags for open_ex() */
344+#define LIBSSH2_SFTP_OPENFILE 0
345+#define LIBSSH2_SFTP_OPENDIR 1
346+
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
351+
352+/* Flags for stat_ex() */
353+#define LIBSSH2_SFTP_STAT 0
354+#define LIBSSH2_SFTP_LSTAT 1
355+#define LIBSSH2_SFTP_SETSTAT 2
356+
357+/* Flags for symlink_ex() */
358+#define LIBSSH2_SFTP_SYMLINK 0
359+#define LIBSSH2_SFTP_READLINK 1
360+#define LIBSSH2_SFTP_REALPATH 2
361+
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
368+
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
372+ */
373+ unsigned long flags;
374+
375+ libssh2_uint64_t filesize;
376+ unsigned long uid, gid;
377+ unsigned long permissions;
378+ unsigned long atime, mtime;
379+};
380+
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
391+
392+/*
393+ * Reproduce the POSIX file modes here for systems that are not
394+ * POSIX compliant.
395+ *
396+ * These is used in "permissions" of "struct _LIBSSH2_SFTP_ATTRIBUTES"
397+ */
398+/* File type */
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 */
407+
408+/* File mode */
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 */
424+
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
433+
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
459+
460+/* Returned by any function that would block during a read/write opperation */
461+#define LIBSSH2SFTP_EAGAIN LIBSSH2_ERROR_EAGAIN
462+
463+/* SFTP API */
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);
467+
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)
475+
476+LIBSSH2_API ssize_t libssh2_sftp_read(LIBSSH2_SFTP_HANDLE *handle, char *buffer, size_t buffer_maxlen);
477+
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))
483+
484+LIBSSH2_API ssize_t libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *buffer, size_t count);
485+
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)
489+
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)
493+
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);
496+
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)
500+
501+
502+
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,
506+ long flags);
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)
509+
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))
512+
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))
515+
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))
518+
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))
523+
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)
528+
529+#ifdef __cplusplus
530+} /* extern "C" */
531+#endif
532+
533+#endif /* LIBSSH2_SFTP_H */
534
535Property changes on: libssh2/include/libssh2_sftp.h
536___________________________________________________________________
537Added: svn:mime-type
538 + text/x-c
539Added: svn:keywords
540 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
541Added: cvs2svn:cvs-rev
542 + 1.2
543Added: svn:eol-style
544 + native
545
546Index: libssh2/include/libssh2.h
547===================================================================
548--- libssh2/include/libssh2.h (.../tags/RELEASE_0_11_0)
549+++ libssh2/include/libssh2.h (.../trunk)
550@@ -0,0 +1,489 @@
551+/* Copyright (c) 2004-2008, Sara Golemon <sarag@libssh2.org>
552+ * All rights reserved.
553+ *
554+ * Redistribution and use in source and binary forms,
555+ * with or without modification, are permitted provided
556+ * that the following conditions are met:
557+ *
558+ * Redistributions of source code must retain the above
559+ * copyright notice, this list of conditions and the
560+ * following disclaimer.
561+ *
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.
566+ *
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.
571+ *
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
585+ * OF SUCH DAMAGE.
586+ */
587+
588+#ifndef LIBSSH2_H
589+#define LIBSSH2_H 1
590+
591+#ifdef __cplusplus
592+extern "C" {
593+#endif
594+
595+#include <stddef.h>
596+#include <string.h>
597+#include <sys/stat.h>
598+#include <sys/types.h>
599+
600+/* Allow alternate API prefix from CFLAGS or calling app */
601+#ifndef LIBSSH2_API
602+# ifdef LIBSSH2_WIN32
603+# ifdef LIBSSH2_LIBRARY
604+# define LIBSSH2_API __declspec(dllexport)
605+# else
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 */
612+
613+#if defined(LIBSSH2_DARWIN) || (defined(LIBSSH2_WIN32) && !defined(_MSC_VER) && !defined(__MINGW32__))
614+# include <sys/uio.h>
615+#endif
616+
617+#if (defined(NETWARE) && !defined(__NOVELL_LIBC__))
618+# include <sys/bsdskt.h>
619+typedef unsigned int uint32_t;
620+#endif
621+
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
629+#endif
630+#else
631+typedef unsigned long long libssh2_uint64_t;
632+typedef long long libssh2_int64_t;
633+#endif
634+
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"
640+
641+/* The numeric version number is also available "in parts" by using these
642+ defines: */
643+#define LIBSSH2_VERSION_MAJOR 1
644+#define LIBSSH2_VERSION_MINOR 0
645+#define LIBSSH2_VERSION_PATCH
646+
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:
650+
651+ 0xXXYYZZ
652+
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".
657+
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.
661+*/
662+#define LIBSSH2_VERSION_NUM 0x010000
663+
664+/*
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.
668+ *
669+ * The format of the date should follow this template:
670+ *
671+ * "Mon Feb 12 11:35:33 UTC 2007"
672+ */
673+#define LIBSSH2_TIMESTAMP "Fri Dec 26 21:35:07 UTC 2008"
674+
675+/* Part of every banner, user specified or not */
676+#define LIBSSH2_SSH_BANNER "SSH-2.0-libssh2_" LIBSSH2_VERSION
677+
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"
681+
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
686+
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
692+
693+/* 1/4 second */
694+#define LIBSSH2_SOCKET_POLL_UDELAY 250000
695+/* 0.25 * 120 == 30 seconds */
696+#define LIBSSH2_SOCKET_POLL_MAXLOOPS 120
697+
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
700+
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
703+
704+/* Maximum size for an inbound compressed payload, plays it safe by overshooting spec limits */
705+#define LIBSSH2_PACKET_MAXPAYLOAD 40000
706+
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)
711+
712+typedef struct _LIBSSH2_USERAUTH_KBDINT_PROMPT
713+{
714+ char* text;
715+ unsigned int length;
716+ unsigned char echo;
717+} LIBSSH2_USERAUTH_KBDINT_PROMPT;
718+
719+typedef struct _LIBSSH2_USERAUTH_KBDINT_RESPONSE
720+{
721+ char* text;
722+ unsigned int length;
723+} LIBSSH2_USERAUTH_KBDINT_RESPONSE;
724+
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)
727+
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)
735+
736+#define LIBSSH2_CHANNEL_CLOSE_FUNC(name) void name(LIBSSH2_SESSION *session, void **session_abstract, LIBSSH2_CHANNEL *channel, void **channel_abstract)
737+
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
744+
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
756+
757+/* session.flags bits */
758+#define LIBSSH2_FLAG_SIGPIPE 0x00000001
759+
760+typedef struct _LIBSSH2_SESSION LIBSSH2_SESSION;
761+typedef struct _LIBSSH2_CHANNEL LIBSSH2_CHANNEL;
762+typedef struct _LIBSSH2_LISTENER LIBSSH2_LISTENER;
763+
764+typedef struct _LIBSSH2_POLLFD {
765+ unsigned char type; /* LIBSSH2_POLLFD_* below */
766+
767+ union {
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? */
771+ } fd;
772+
773+ unsigned long events; /* Requested Events */
774+ unsigned long revents; /* Returned Events */
775+} LIBSSH2_POLLFD;
776+
777+/* Poll FD Descriptor Types */
778+#define LIBSSH2_POLLFD_SOCKET 1
779+#define LIBSSH2_POLLFD_CHANNEL 2
780+#define LIBSSH2_POLLFD_LISTENER 3
781+
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 */
788+/* revents only */
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 */
796+
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
801+
802+/* Hash Types */
803+#define LIBSSH2_HOSTKEY_HASH_MD5 1
804+#define LIBSSH2_HOSTKEY_HASH_SHA1 2
805+
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
822+
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
862+
863+/* Session API */
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);
867+
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);
870+
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);
875+
876+LIBSSH2_API const char *libssh2_hostkey_hash(LIBSSH2_SESSION *session, int hash_type);
877+
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);
883+
884+LIBSSH2_API int libssh2_session_flag(LIBSSH2_SESSION *session, int flag, int value);
885+
886+/* Userauth API */
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)
891+
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))
904+
905+/*
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.
910+ */
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))
915+
916+LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds, long timeout);
917+
918+/* Channel API */
919+#define LIBSSH2_CHANNEL_WINDOW_DEFAULT 65536
920+#define LIBSSH2_CHANNEL_PACKET_DEFAULT 16384
921+#define LIBSSH2_CHANNEL_MINADJUST 1024
922+
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
927+
928+#define SSH_EXTENDED_DATA_STDERR 1
929+
930+/* Returned by any function that would block during a read/write opperation */
931+#define LIBSSH2CHANNEL_EAGAIN LIBSSH2_ERROR_EAGAIN
932+
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)
935+
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)
938+
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)
941+
942+LIBSSH2_API int libssh2_channel_forward_cancel(LIBSSH2_LISTENER *listener);
943+
944+LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_forward_accept(LIBSSH2_LISTENER *listener);
945+
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))
948+
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)
951+
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)
954+
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))
957+
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))
962+
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))
968+
969+LIBSSH2_API int libssh2_poll_channel_read(LIBSSH2_CHANNEL *channel, int extended);
970+
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)
974+
975+LIBSSH2_API unsigned long libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL *channel, unsigned long adjustment, unsigned char force);
976+
977+LIBSSH2_API ssize_t libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel, int stream_id, const char *buf, size_t buflen);
978+
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))
983+
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)
986+
987+LIBSSH2_API void libssh2_session_set_blocking(LIBSSH2_SESSION* session, int blocking);
988+LIBSSH2_API int libssh2_session_get_blocking(LIBSSH2_SESSION* session);
989+
990+LIBSSH2_API void libssh2_channel_set_blocking(LIBSSH2_CHANNEL *channel, int blocking);
991+
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
997+ */
998+/* DEPRECATED */
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 )
1000+
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);
1007+
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);
1014+
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)
1018+
1019+LIBSSH2_API int libssh2_base64_decode(LIBSSH2_SESSION *session, char **dest, unsigned int *dest_len, const char *src, unsigned int src_len);
1020+
1021+/* NOTE NOTE NOTE
1022+ libssh2_trace() has no function in builds that aren't built with debug
1023+ enabled
1024+ */
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)
1034+
1035+#ifdef __cplusplus
1036+} /* extern "C" */
1037+#endif
1038+
1039+#endif /* LIBSSH2_H */
1040
1041Property changes on: libssh2/include/libssh2.h
1042___________________________________________________________________
1043Added: svn:mime-type
1044 + text/x-c
1045Added: svn:keywords
1046 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
1047Added: cvs2svn:cvs-rev
1048 + 1.3
1049Added: svn:eol-style
1050 + native
1051
1052Index: libssh2/src/comp.c
1053===================================================================
1054--- libssh2/src/comp.c (.../tags/RELEASE_0_11_0)
1055+++ libssh2/src/comp.c (.../trunk)
1056@@ -0,0 +1,340 @@
1057+/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
1058+ * All rights reserved.
1059+ *
1060+ * Redistribution and use in source and binary forms,
1061+ * with or without modification, are permitted provided
1062+ * that the following conditions are met:
1063+ *
1064+ * Redistributions of source code must retain the above
1065+ * copyright notice, this list of conditions and the
1066+ * following disclaimer.
1067+ *
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.
1072+ *
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.
1077+ *
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
1091+ * OF SUCH DAMAGE.
1092+ */
1093+
1094+#include "libssh2_priv.h"
1095+#ifdef LIBSSH2_HAVE_ZLIB
1096+# include <zlib.h>
1097+#endif
1098+
1099+/* ********
1100+ * none *
1101+ ******** */
1102+
1103+/* {{{ libssh2_comp_method_none_comp
1104+ * Minimalist compression: Absolutely none
1105+ */
1106+static int
1107+libssh2_comp_method_none_comp(LIBSSH2_SESSION * session,
1108+ int compress,
1109+ unsigned char **dest,
1110+ unsigned long *dest_len,
1111+ unsigned long payload_limit,
1112+ int *free_dest,
1113+ const unsigned char *src,
1114+ unsigned long src_len, void **abstract)
1115+{
1116+ (void) session;
1117+ (void) compress;
1118+ (void) payload_limit;
1119+ (void) abstract;
1120+ *dest = (unsigned char *) src;
1121+ *dest_len = src_len;
1122+
1123+ *free_dest = 0;
1124+
1125+ return 0;
1126+}
1127+
1128+/* }}} */
1129+
1130+static const LIBSSH2_COMP_METHOD libssh2_comp_method_none = {
1131+ "none",
1132+ NULL,
1133+ libssh2_comp_method_none_comp,
1134+ NULL
1135+};
1136+
1137+#ifdef LIBSSH2_HAVE_ZLIB
1138+/* ********
1139+ * zlib *
1140+ ******** */
1141+
1142+/* {{{ Memory management wrappers
1143+ * Yes, I realize we're doing a callback to a callback,
1144+ * Deal...
1145+ */
1146+
1147+static voidpf
1148+libssh2_comp_method_zlib_alloc(voidpf opaque, uInt items, uInt size)
1149+{
1150+ LIBSSH2_SESSION *session = (LIBSSH2_SESSION *) opaque;
1151+
1152+ return (voidpf) LIBSSH2_ALLOC(session, items * size);
1153+}
1154+
1155+static void
1156+libssh2_comp_method_zlib_free(voidpf opaque, voidpf address)
1157+{
1158+ LIBSSH2_SESSION *session = (LIBSSH2_SESSION *) opaque;
1159+
1160+ LIBSSH2_FREE(session, address);
1161+}
1162+
1163+/* }}} */
1164+
1165+/* {{{ libssh2_comp_method_zlib_init
1166+ * All your bandwidth are belong to us (so save some)
1167+ */
1168+static int
1169+libssh2_comp_method_zlib_init(LIBSSH2_SESSION * session, int compress,
1170+ void **abstract)
1171+{
1172+ z_stream *strm;
1173+ int status;
1174+
1175+ strm = LIBSSH2_ALLOC(session, sizeof(z_stream));
1176+ if (!strm) {
1177+ libssh2_error(session, LIBSSH2_ERROR_ALLOC,
1178+ "Unable to allocate memory for zlib compression/decompression",
1179+ 0);
1180+ return -1;
1181+ }
1182+ memset(strm, 0, sizeof(z_stream));
1183+
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;
1187+ if (compress) {
1188+ /* deflate */
1189+ status = deflateInit(strm, Z_DEFAULT_COMPRESSION);
1190+ } else {
1191+ /* inflate */
1192+ status = inflateInit(strm);
1193+ }
1194+
1195+ if (status != Z_OK) {
1196+ LIBSSH2_FREE(session, strm);
1197+ return -1;
1198+ }
1199+ *abstract = strm;
1200+
1201+ return 0;
1202+}
1203+
1204+/* }}} */
1205+
1206+/* {{{ libssh2_comp_method_zlib_comp
1207+ * zlib, a compression standard for all occasions
1208+ */
1209+static int
1210+libssh2_comp_method_zlib_comp(LIBSSH2_SESSION * session,
1211+ int compress,
1212+ unsigned char **dest,
1213+ unsigned long *dest_len,
1214+ unsigned long payload_limit,
1215+ int *free_dest,
1216+ const unsigned char *src,
1217+ unsigned long src_len, void **abstract)
1218+{
1219+ z_stream *strm = *abstract;
1220+ /* A short-term alloc of a full data chunk is better than a series of
1221+ reallocs */
1222+ char *out;
1223+ int out_maxlen = compress ? (src_len + 4) : (2 * src_len);
1224+ int limiter = 0;
1225+
1226+ /* In practice they never come smaller than this */
1227+ if (out_maxlen < 25) {
1228+ out_maxlen = 25;
1229+ }
1230+
1231+ if (out_maxlen > (int) payload_limit) {
1232+ out_maxlen = payload_limit;
1233+ }
1234+
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",
1243+ 0);
1244+ return -1;
1245+ }
1246+ while (strm->avail_in) {
1247+ int status;
1248+
1249+ if (compress) {
1250+ status = deflate(strm, Z_PARTIAL_FLUSH);
1251+ } else {
1252+ status = inflate(strm, Z_PARTIAL_FLUSH);
1253+ }
1254+ if (status != Z_OK) {
1255+ libssh2_error(session, LIBSSH2_ERROR_ZLIB,
1256+ "compress/decompression failure", 0);
1257+ LIBSSH2_FREE(session, out);
1258+ return -1;
1259+ }
1260+ if (strm->avail_in) {
1261+ unsigned long out_ofs = out_maxlen - strm->avail_out;
1262+ char *newout;
1263+
1264+ out_maxlen +=
1265+ compress ? (strm->avail_in + 4) : (2 * strm->avail_in);
1266+
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);
1271+ return -1;
1272+ }
1273+
1274+ newout = LIBSSH2_REALLOC(session, out, out_maxlen);
1275+ if (!newout) {
1276+ libssh2_error(session, LIBSSH2_ERROR_ALLOC,
1277+ "Unable to expand compress/decompression buffer",
1278+ 0);
1279+ LIBSSH2_FREE(session, out);
1280+ return -1;
1281+ }
1282+ out = newout;
1283+ strm->next_out = (unsigned char *) out + out_ofs;
1284+ strm->avail_out +=
1285+ compress ? (strm->avail_in + 4) : (2 * strm->avail_in);
1286+ } else
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
1290+ */
1291+ int grow_size = compress ? 8 : 1024;
1292+ char *newout;
1293+
1294+ if (out_maxlen >= (int) payload_limit) {
1295+ libssh2_error(session, LIBSSH2_ERROR_ZLIB,
1296+ "Excessive growth in decompression phase",
1297+ 0);
1298+ LIBSSH2_FREE(session, out);
1299+ return -1;
1300+ }
1301+
1302+ if (grow_size > (int) (payload_limit - out_maxlen)) {
1303+ grow_size = payload_limit - out_maxlen;
1304+ }
1305+
1306+ out_maxlen += grow_size;
1307+ strm->avail_out = grow_size;
1308+
1309+ newout = LIBSSH2_REALLOC(session, out, out_maxlen);
1310+ if (!newout) {
1311+ libssh2_error(session, LIBSSH2_ERROR_ALLOC,
1312+ "Unable to expand final compress/decompress buffer",
1313+ 0);
1314+ LIBSSH2_FREE(session, out);
1315+ return -1;
1316+ }
1317+ out = newout;
1318+ strm->next_out = (unsigned char *) out + out_maxlen -
1319+ grow_size;
1320+
1321+ if (compress) {
1322+ status = deflate(strm, Z_PARTIAL_FLUSH);
1323+ } else {
1324+ status = inflate(strm, Z_PARTIAL_FLUSH);
1325+ }
1326+ if (status != Z_OK) {
1327+ libssh2_error(session, LIBSSH2_ERROR_ZLIB,
1328+ "compress/decompression failure", 0);
1329+ LIBSSH2_FREE(session, out);
1330+ return -1;
1331+ }
1332+ }
1333+ }
1334+
1335+ *dest = (unsigned char *) out;
1336+ *dest_len = out_maxlen - strm->avail_out;
1337+ *free_dest = 1;
1338+
1339+ return 0;
1340+}
1341+
1342+/* }}} */
1343+
1344+/* {{{ libssh2_comp_method_zlib_dtor
1345+ * All done, no more compression for you
1346+ */
1347+static int
1348+libssh2_comp_method_zlib_dtor(LIBSSH2_SESSION * session, int compress,
1349+ void **abstract)
1350+{
1351+ z_stream *strm = *abstract;
1352+
1353+ if (strm) {
1354+ if (compress) {
1355+ /* deflate */
1356+ deflateEnd(strm);
1357+ } else {
1358+ /* inflate */
1359+ inflateEnd(strm);
1360+ }
1361+
1362+ LIBSSH2_FREE(session, strm);
1363+ }
1364+
1365+ *abstract = NULL;
1366+
1367+ return 0;
1368+}
1369+
1370+/* }}} */
1371+
1372+static const LIBSSH2_COMP_METHOD libssh2_comp_method_zlib = {
1373+ "zlib",
1374+ libssh2_comp_method_zlib_init,
1375+ libssh2_comp_method_zlib_comp,
1376+ libssh2_comp_method_zlib_dtor,
1377+};
1378+#endif /* LIBSSH2_HAVE_ZLIB */
1379+
1380+/* ***********************
1381+ * Compression Methods *
1382+ *********************** */
1383+
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 */
1389+ NULL
1390+};
1391+
1392+const LIBSSH2_COMP_METHOD **
1393+libssh2_comp_methods(void)
1394+{
1395+ return _libssh2_comp_methods;
1396+}
1397
1398Property changes on: libssh2/src/comp.c
1399___________________________________________________________________
1400Added: svn:mime-type
1401 + text/x-c
1402Added: svn:keywords
1403 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
1404Added: cvs2svn:cvs-rev
1405 + 1.2
1406Added: svn:eol-style
1407 + native
1408
1409Index: libssh2/src/libgcrypt.c
1410===================================================================
1411--- libssh2/src/libgcrypt.c (.../tags/RELEASE_0_11_0)
1412+++ libssh2/src/libgcrypt.c (.../trunk)
1413@@ -0,0 +1,560 @@
1414+/* Copyright (C) 2006, 2007, The Written Word, Inc.
1415+ * Copyright (C) 2008, Simon Josefsson
1416+ * All rights reserved.
1417+ *
1418+ * Redistribution and use in source and binary forms,
1419+ * with or without modification, are permitted provided
1420+ * that the following conditions are met:
1421+ *
1422+ * Redistributions of source code must retain the above
1423+ * copyright notice, this list of conditions and the
1424+ * following disclaimer.
1425+ *
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.
1430+ *
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.
1435+ *
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
1449+ * OF SUCH DAMAGE.
1450+ */
1451+
1452+#include "libssh2_priv.h"
1453+#include <string.h>
1454+
1455+int
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)
1472+{
1473+ int rc;
1474+ (void) e1data;
1475+ (void) e1len;
1476+ (void) e2data;
1477+ (void) e2len;
1478+
1479+ if (ddata) {
1480+ rc = gcry_sexp_build
1481+ (rsa, NULL,
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);
1485+ } else {
1486+ rc = gcry_sexp_build(rsa, NULL, "(public-key(rsa(n%b)(e%b)))",
1487+ nlen, ndata, elen, edata);
1488+ }
1489+ if (rc) {
1490+ *rsa = NULL;
1491+ return -1;
1492+ }
1493+
1494+ return 0;
1495+}
1496+
1497+int
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)
1502+{
1503+ unsigned char hash[SHA_DIGEST_LENGTH];
1504+ gcry_sexp_t s_sig, s_hash;
1505+ int rc = -1;
1506+
1507+ libssh2_sha1(m, m_len, hash);
1508+
1509+ rc = gcry_sexp_build(&s_hash, NULL,
1510+ "(data (flags pkcs1) (hash sha1 %b))",
1511+ SHA_DIGEST_LENGTH, hash);
1512+ if (rc != 0) {
1513+ return -1;
1514+ }
1515+
1516+ rc = gcry_sexp_build(&s_sig, NULL, "(sig-val(rsa(s %b)))", sig_len, sig);
1517+ if (rc != 0) {
1518+ gcry_sexp_release(s_hash);
1519+ return -1;
1520+ }
1521+
1522+ rc = gcry_pk_verify(s_sig, s_hash, rsa);
1523+ gcry_sexp_release(s_sig);
1524+ gcry_sexp_release(s_hash);
1525+
1526+ return (rc == 0) ? 0 : -1;
1527+}
1528+
1529+int
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)
1540+{
1541+ int rc;
1542+
1543+ if (x_len) {
1544+ rc = gcry_sexp_build
1545+ (dsactx, NULL,
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);
1548+ } else {
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);
1552+ }
1553+
1554+ if (rc) {
1555+ *dsactx = NULL;
1556+ return -1;
1557+ }
1558+
1559+ return 0;
1560+}
1561+
1562+int
1563+_libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa,
1564+ LIBSSH2_SESSION * session,
1565+ FILE * fp, unsigned const char *passphrase)
1566+{
1567+ unsigned char *data, *save_data;
1568+ unsigned int datalen;
1569+ int ret;
1570+ unsigned char *n, *e, *d, *p, *q, *e1, *e2, *coeff;
1571+ unsigned int nlen, elen, dlen, plen, qlen, e1len, e2len, coefflen;
1572+
1573+ (void) passphrase;
1574+
1575+ ret = _libssh2_pem_parse(session,
1576+ "-----BEGIN RSA PRIVATE KEY-----",
1577+ "-----END RSA PRIVATE KEY-----",
1578+ fp, &data, &datalen);
1579+ if (ret) {
1580+ return -1;
1581+ }
1582+
1583+ save_data = data;
1584+
1585+ if (_libssh2_pem_decode_sequence(&data, &datalen)) {
1586+ ret = -1;
1587+ goto fail;
1588+ }
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')) {
1592+ ret = -1;
1593+ goto fail;
1594+ }
1595+
1596+ ret = _libssh2_pem_decode_integer(&data, &datalen, &n, &nlen);
1597+ if (ret != 0) {
1598+ ret = -1;
1599+ goto fail;
1600+ }
1601+
1602+ ret = _libssh2_pem_decode_integer(&data, &datalen, &e, &elen);
1603+ if (ret != 0) {
1604+ ret = -1;
1605+ goto fail;
1606+ }
1607+
1608+ ret = _libssh2_pem_decode_integer(&data, &datalen, &d, &dlen);
1609+ if (ret != 0) {
1610+ ret = -1;
1611+ goto fail;
1612+ }
1613+
1614+ ret = _libssh2_pem_decode_integer(&data, &datalen, &p, &plen);
1615+ if (ret != 0) {
1616+ ret = -1;
1617+ goto fail;
1618+ }
1619+
1620+ ret = _libssh2_pem_decode_integer(&data, &datalen, &q, &qlen);
1621+ if (ret != 0) {
1622+ ret = -1;
1623+ goto fail;
1624+ }
1625+
1626+ ret = _libssh2_pem_decode_integer(&data, &datalen, &e1, &e1len);
1627+ if (ret != 0) {
1628+ ret = -1;
1629+ goto fail;
1630+ }
1631+
1632+ ret = _libssh2_pem_decode_integer(&data, &datalen, &e2, &e2len);
1633+ if (ret != 0) {
1634+ ret = -1;
1635+ goto fail;
1636+ }
1637+
1638+ ret = _libssh2_pem_decode_integer(&data, &datalen, &coeff, &coefflen);
1639+ if (ret != 0) {
1640+ ret = -1;
1641+ goto fail;
1642+ }
1643+
1644+ if (_libssh2_rsa_new(rsa, e, elen, n, nlen, d, dlen, p, plen,
1645+ q, qlen, e1, e1len, e2, e2len, coeff, coefflen)) {
1646+ ret = -1;
1647+ goto fail;
1648+ }
1649+
1650+ ret = 0;
1651+
1652+ fail:
1653+ LIBSSH2_FREE(session, save_data);
1654+ return ret;
1655+}
1656+
1657+int
1658+_libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa,
1659+ LIBSSH2_SESSION * session,
1660+ FILE * fp, unsigned const char *passphrase)
1661+{
1662+ unsigned char *data, *save_data;
1663+ unsigned int datalen;
1664+ int ret;
1665+ unsigned char *p, *q, *g, *y, *x;
1666+ unsigned int plen, qlen, glen, ylen, xlen;
1667+
1668+ (void) passphrase;
1669+
1670+ ret = _libssh2_pem_parse(session,
1671+ "-----BEGIN DSA PRIVATE KEY-----",
1672+ "-----END DSA PRIVATE KEY-----",
1673+ fp, &data, &datalen);
1674+ if (ret) {
1675+ return -1;
1676+ }
1677+
1678+ save_data = data;
1679+
1680+ if (_libssh2_pem_decode_sequence(&data, &datalen)) {
1681+ ret = -1;
1682+ goto fail;
1683+ }
1684+
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')) {
1688+ ret = -1;
1689+ goto fail;
1690+ }
1691+
1692+ ret = _libssh2_pem_decode_integer(&data, &datalen, &p, &plen);
1693+ if (ret != 0) {
1694+ ret = -1;
1695+ goto fail;
1696+ }
1697+
1698+ ret = _libssh2_pem_decode_integer(&data, &datalen, &q, &qlen);
1699+ if (ret != 0) {
1700+ ret = -1;
1701+ goto fail;
1702+ }
1703+
1704+ ret = _libssh2_pem_decode_integer(&data, &datalen, &g, &glen);
1705+ if (ret != 0) {
1706+ ret = -1;
1707+ goto fail;
1708+ }
1709+
1710+ ret = _libssh2_pem_decode_integer(&data, &datalen, &y, &ylen);
1711+ if (ret != 0) {
1712+ ret = -1;
1713+ goto fail;
1714+ }
1715+
1716+ ret = _libssh2_pem_decode_integer(&data, &datalen, &x, &xlen);
1717+ if (ret != 0) {
1718+ ret = -1;
1719+ goto fail;
1720+ }
1721+
1722+ if (datalen != 0) {
1723+ ret = -1;
1724+ goto fail;
1725+ }
1726+
1727+ if (_libssh2_dsa_new(dsa, p, plen, q, qlen, g, glen, y, ylen, x, xlen)) {
1728+ ret = -1;
1729+ goto fail;
1730+ }
1731+
1732+ ret = 0;
1733+
1734+ fail:
1735+ LIBSSH2_FREE(session, save_data);
1736+ return ret;
1737+}
1738+
1739+int
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)
1745+{
1746+ gcry_sexp_t sig_sexp;
1747+ gcry_sexp_t data;
1748+ int rc;
1749+ const char *tmp;
1750+ size_t size;
1751+
1752+ if (hash_len != SHA_DIGEST_LENGTH) {
1753+ return -1;
1754+ }
1755+
1756+ if (gcry_sexp_build(&data, NULL,
1757+ "(data (flags pkcs1) (hash sha1 %b))",
1758+ hash_len, hash)) {
1759+ return -1;
1760+ }
1761+
1762+ rc = gcry_pk_sign(&sig_sexp, data, rsactx);
1763+
1764+ gcry_sexp_release(data);
1765+
1766+ if (rc != 0) {
1767+ return -1;
1768+ }
1769+
1770+ data = gcry_sexp_find_token(sig_sexp, "s", 0);
1771+ if (!data) {
1772+ return -1;
1773+ }
1774+
1775+ tmp = gcry_sexp_nth_data(data, 1, &size);
1776+ if (!tmp) {
1777+ return -1;
1778+ }
1779+
1780+ if (tmp[0] == '\0') {
1781+ tmp++;
1782+ size--;
1783+ }
1784+
1785+ *signature = LIBSSH2_ALLOC(session, size);
1786+ memcpy(*signature, tmp, size);
1787+ *signature_len = size;
1788+
1789+ return rc;
1790+}
1791+
1792+int
1793+_libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,
1794+ const unsigned char *hash,
1795+ unsigned long hash_len, unsigned char *sig)
1796+{
1797+ unsigned char zhash[SHA_DIGEST_LENGTH + 1];
1798+ gcry_sexp_t sig_sexp;
1799+ gcry_sexp_t data;
1800+ int ret;
1801+ const char *tmp;
1802+ size_t size;
1803+
1804+ if (hash_len != SHA_DIGEST_LENGTH) {
1805+ return -1;
1806+ }
1807+
1808+ memcpy(zhash + 1, hash, hash_len);
1809+ zhash[0] = 0;
1810+
1811+ if (gcry_sexp_build(&data, NULL, "(data (value %b))", hash_len + 1, zhash)) {
1812+ return -1;
1813+ }
1814+
1815+ ret = gcry_pk_sign(&sig_sexp, data, dsactx);
1816+
1817+ gcry_sexp_release(data);
1818+
1819+ if (ret != 0) {
1820+ return -1;
1821+ }
1822+
1823+/* Extract R. */
1824+
1825+ data = gcry_sexp_find_token(sig_sexp, "r", 0);
1826+ if (!data) {
1827+ ret = -1;
1828+ goto out;
1829+ }
1830+
1831+ tmp = gcry_sexp_nth_data(data, 1, &size);
1832+ if (!tmp) {
1833+ ret = -1;
1834+ goto out;
1835+ }
1836+
1837+ if (tmp[0] == '\0') {
1838+ tmp++;
1839+ size--;
1840+ }
1841+
1842+ if (size != 20) {
1843+ ret = -1;
1844+ goto out;
1845+ }
1846+
1847+ memcpy(sig, tmp, 20);
1848+
1849+ gcry_sexp_release(data);
1850+
1851+/* Extract S. */
1852+
1853+ data = gcry_sexp_find_token(sig_sexp, "s", 0);
1854+ if (!data) {
1855+ ret = -1;
1856+ goto out;
1857+ }
1858+
1859+ tmp = gcry_sexp_nth_data(data, 1, &size);
1860+ if (!tmp) {
1861+ ret = -1;
1862+ goto out;
1863+ }
1864+
1865+ if (tmp[0] == '\0') {
1866+ tmp++;
1867+ size--;
1868+ }
1869+
1870+ if (size != 20) {
1871+ ret = -1;
1872+ goto out;
1873+ }
1874+
1875+ memcpy(sig + 20, tmp, 20);
1876+
1877+ ret = 0;
1878+ out:
1879+ if (sig_sexp) {
1880+ gcry_sexp_release(sig_sexp);
1881+ }
1882+ if (data) {
1883+ gcry_sexp_release(data);
1884+ }
1885+ return ret;
1886+}
1887+
1888+int
1889+_libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx,
1890+ const unsigned char *sig,
1891+ const unsigned char *m, unsigned long m_len)
1892+{
1893+ unsigned char hash[SHA_DIGEST_LENGTH + 1];
1894+ gcry_sexp_t s_sig, s_hash;
1895+ int rc = -1;
1896+
1897+ libssh2_sha1(m, m_len, hash + 1);
1898+ hash[0] = 0;
1899+
1900+ if (gcry_sexp_build(&s_hash, NULL, "(data(flags raw)(value %b))",
1901+ SHA_DIGEST_LENGTH + 1, hash)) {
1902+ return -1;
1903+ }
1904+
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);
1908+ return -1;
1909+ }
1910+
1911+ rc = gcry_pk_verify(s_sig, s_hash, dsactx);
1912+ gcry_sexp_release(s_sig);
1913+ gcry_sexp_release(s_hash);
1914+
1915+ return (rc == 0) ? 0 : -1;
1916+}
1917+
1918+int
1919+_libssh2_cipher_init(_libssh2_cipher_ctx * h,
1920+ _libssh2_cipher_type(algo),
1921+ unsigned char *iv, unsigned char *secret, int encrypt)
1922+{
1923+ int mode = 0, ret;
1924+ int keylen = gcry_cipher_get_algo_keylen(algo);
1925+
1926+ (void) encrypt;
1927+
1928+ if (algo != GCRY_CIPHER_ARCFOUR) {
1929+ mode = GCRY_CIPHER_MODE_CBC;
1930+ }
1931+
1932+ ret = gcry_cipher_open(h, algo, mode, 0);
1933+ if (ret) {
1934+ return -1;
1935+ }
1936+
1937+ ret = gcry_cipher_setkey(*h, secret, keylen);
1938+ if (ret) {
1939+ gcry_cipher_close(*h);
1940+ return -1;
1941+ }
1942+
1943+ if (algo != GCRY_CIPHER_ARCFOUR) {
1944+ int blklen = gcry_cipher_get_algo_blklen(algo);
1945+ ret = gcry_cipher_setiv(*h, iv, blklen);
1946+ if (ret) {
1947+ gcry_cipher_close(*h);
1948+ return -1;
1949+ }
1950+ }
1951+
1952+ return 0;
1953+}
1954+
1955+int
1956+_libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx,
1957+ _libssh2_cipher_type(algo),
1958+ int encrypt, unsigned char *block)
1959+{
1960+ size_t blklen = gcry_cipher_get_algo_blklen(algo);
1961+ int ret;
1962+ if (blklen == 1) {
1963+/* Hack for arcfour. */
1964+ blklen = 8;
1965+ }
1966+
1967+ if (encrypt) {
1968+ ret = gcry_cipher_encrypt(*ctx, block, blklen, block, blklen);
1969+ } else {
1970+ ret = gcry_cipher_decrypt(*ctx, block, blklen, block, blklen);
1971+ }
1972+ return ret;
1973+}
1974
1975Property changes on: libssh2/src/libgcrypt.c
1976___________________________________________________________________
1977Added: svn:mime-type
1978 + text/x-c
1979Added: svn:keywords
1980 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
1981Added: cvs2svn:cvs-rev
1982 + 1.1
1983Added: svn:eol-style
1984 + native
1985Added: svn:executable
1986 + *
1987
1988Index: libssh2/src/userauth.c
1989===================================================================
1990--- libssh2/src/userauth.c (.../tags/RELEASE_0_11_0)
1991+++ libssh2/src/userauth.c (.../trunk)
1992@@ -0,0 +1,1473 @@
1993+/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
1994+ * All rights reserved.
1995+ *
1996+ * Redistribution and use in source and binary forms,
1997+ * with or without modification, are permitted provided
1998+ * that the following conditions are met:
1999+ *
2000+ * Redistributions of source code must retain the above
2001+ * copyright notice, this list of conditions and the
2002+ * following disclaimer.
2003+ *
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.
2008+ *
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.
2013+ *
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
2027+ * OF SUCH DAMAGE.
2028+ */
2029+
2030+#include "libssh2_priv.h"
2031+
2032+#include <ctype.h>
2033+#include <stdio.h>
2034+
2035+/* Needed for struct iovec on some platforms */
2036+#ifdef HAVE_SYS_UIO_H
2037+#include <sys/uio.h>
2038+#endif
2039+
2040+
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
2046+ */
2047+LIBSSH2_API char *
2048+libssh2_userauth_list(LIBSSH2_SESSION * session, const char *username,
2049+ unsigned int username_len)
2050+{
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;
2056+ unsigned char *s;
2057+ int rc;
2058+
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));
2063+
2064+ session->userauth_list_data_len = username_len + 31;
2065+
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);
2071+ return NULL;
2072+ }
2073+
2074+ *(s++) = SSH_MSG_USERAUTH_REQUEST;
2075+ libssh2_htonu32(s, username_len);
2076+ s += 4;
2077+ if (username) {
2078+ memcpy(s, username, username_len);
2079+ s += username_len;
2080+ }
2081+
2082+ libssh2_htonu32(s, 14);
2083+ s += 4;
2084+ memcpy(s, "ssh-connection", 14);
2085+ s += 14;
2086+
2087+ libssh2_htonu32(s, 4);
2088+ s += 4;
2089+ memcpy(s, "none", 4);
2090+ s += 4;
2091+
2092+ session->userauth_list_state = libssh2_NB_state_created;
2093+ }
2094+
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);
2101+ return NULL;
2102+ } else if (rc) {
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;
2108+ return NULL;
2109+ }
2110+ LIBSSH2_FREE(session, session->userauth_list_data);
2111+ session->userauth_list_data = NULL;
2112+
2113+ session->userauth_list_state = libssh2_NB_state_sent;
2114+ }
2115+
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,
2120+ NULL, 0,
2121+ &session->
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);
2126+ return NULL;
2127+ } else if (rc) {
2128+ libssh2_error(session, LIBSSH2_ERROR_NONE, "No error", 0);
2129+ session->userauth_list_state = libssh2_NB_state_idle;
2130+ return NULL;
2131+ }
2132+
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;
2140+ return NULL;
2141+ }
2142+
2143+ methods_len = libssh2_ntohu32(session->userauth_list_data + 1);
2144+
2145+ /* Do note that the memory areas overlap! */
2146+ memmove(session->userauth_list_data, session->userauth_list_data + 5,
2147+ methods_len);
2148+ session->userauth_list_data[methods_len] = '\0';
2149+ _libssh2_debug(session, LIBSSH2_DBG_AUTH, "Permitted auth methods: %s",
2150+ session->userauth_list_data);
2151+ }
2152+
2153+ session->userauth_list_state = libssh2_NB_state_idle;
2154+ return (char *) session->userauth_list_data;
2155+}
2156+
2157+/* }}} */
2158+
2159+/* {{{ libssh2_userauth_authenticated
2160+ * 0 if not yet authenticated
2161+ * non-zero is already authenticated
2162+ */
2163+LIBSSH2_API int
2164+libssh2_userauth_authenticated(LIBSSH2_SESSION * session)
2165+{
2166+ return session->state & LIBSSH2_STATE_AUTHENTICATED;
2167+}
2168+
2169+/* }}} */
2170+
2171+/* {{{ libssh2_userauth_password
2172+ * Plain ol' login
2173+ */
2174+LIBSSH2_API int
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)))
2179+{
2180+ unsigned char *s;
2181+ static const unsigned char reply_codes[4] =
2182+ { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE,
2183+ SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, 0
2184+ };
2185+ int rc;
2186+
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));
2191+
2192+ /*
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;
2197+
2198+ session->userauth_pswd_data0 = ~SSH_MSG_USERAUTH_PASSWD_CHANGEREQ;
2199+
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",
2205+ 0);
2206+ return -1;
2207+ }
2208+
2209+ *(s++) = SSH_MSG_USERAUTH_REQUEST;
2210+ libssh2_htonu32(s, username_len);
2211+ s += 4;
2212+ memcpy(s, username, username_len);
2213+ s += username_len;
2214+
2215+ libssh2_htonu32(s, sizeof("ssh-connection") - 1);
2216+ s += 4;
2217+ memcpy(s, "ssh-connection", sizeof("ssh-connection") - 1);
2218+ s += sizeof("ssh-connection") - 1;
2219+
2220+ libssh2_htonu32(s, sizeof("password") - 1);
2221+ s += 4;
2222+ memcpy(s, "password", sizeof("password") - 1);
2223+ s += sizeof("password") - 1;
2224+
2225+ *s = '\0';
2226+ s++;
2227+
2228+ libssh2_htonu32(s, password_len);
2229+ s += 4;
2230+ memcpy(s, password, password_len);
2231+ s += password_len;
2232+
2233+ _libssh2_debug(session, LIBSSH2_DBG_AUTH,
2234+ "Attempting to login using password authentication");
2235+
2236+ session->userauth_pswd_state = libssh2_NB_state_created;
2237+ }
2238+
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;
2244+ } else if (rc) {
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;
2250+ return -1;
2251+ }
2252+ LIBSSH2_FREE(session, session->userauth_pswd_data);
2253+ session->userauth_pswd_data = NULL;
2254+
2255+ session->userauth_pswd_state = libssh2_NB_state_sent;
2256+ }
2257+
2258+ password_response:
2259+
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,
2267+ 0, NULL, 0,
2268+ &session->
2269+ userauth_pswd_packet_requirev_state);
2270+ if (rc == PACKET_EAGAIN) {
2271+ return PACKET_EAGAIN;
2272+ } else if (rc) {
2273+ session->userauth_pswd_state = libssh2_NB_state_idle;
2274+ return -1;
2275+ }
2276+
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;
2284+ return 0;
2285+ }
2286+
2287+ session->userauth_pswd_newpw = NULL;
2288+ session->userauth_pswd_newpw_len = 0;
2289+
2290+ session->userauth_pswd_state = libssh2_NB_state_sent1;
2291+ }
2292+
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;
2298+
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;
2306+ }
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",
2317+ 0);
2318+ return -1;
2319+ }
2320+
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;
2325+
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",
2332+ 0);
2333+ LIBSSH2_FREE(session,
2334+ session->userauth_pswd_newpw);
2335+ session->userauth_pswd_newpw = NULL;
2336+ return -1;
2337+ }
2338+
2339+ *(s++) = SSH_MSG_USERAUTH_REQUEST;
2340+ libssh2_htonu32(s, username_len);
2341+ s += 4;
2342+ memcpy(s, username, username_len);
2343+ s += username_len;
2344+
2345+ libssh2_htonu32(s, sizeof("ssh-connection") - 1);
2346+ s += 4;
2347+ memcpy(s, "ssh-connection",
2348+ sizeof("ssh-connection") - 1);
2349+ s += sizeof("ssh-connection") - 1;
2350+
2351+ libssh2_htonu32(s, sizeof("password") - 1);
2352+ s += 4;
2353+ memcpy(s, "password", sizeof("password") - 1);
2354+ s += sizeof("password") - 1;
2355+
2356+ *s = 0x01;
2357+ s++;
2358+
2359+ libssh2_htonu32(s, password_len);
2360+ s += 4;
2361+ memcpy(s, password, password_len);
2362+ s += password_len;
2363+
2364+ libssh2_htonu32(s, session->userauth_pswd_newpw_len);
2365+ s += 4;
2366+ memcpy(s, session->userauth_pswd_newpw,
2367+ session->userauth_pswd_newpw_len);
2368+ s += session->userauth_pswd_newpw_len;
2369+
2370+ session->userauth_pswd_state = libssh2_NB_state_sent2;
2371+ }
2372+
2373+ if (session->userauth_pswd_state == libssh2_NB_state_sent2) {
2374+ rc = libssh2_packet_write(session,
2375+ session->userauth_pswd_data,
2376+ session->
2377+ userauth_pswd_data_len);
2378+ if (rc == PACKET_EAGAIN) {
2379+ return PACKET_EAGAIN;
2380+ } else if (rc) {
2381+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
2382+ "Unable to send userauth-password-change request",
2383+ 0);
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;
2389+ return -1;
2390+ }
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;
2395+
2396+ /*
2397+ * Ugliest use of goto ever. Blame it on the
2398+ * askN => requirev migration.
2399+ */
2400+ session->userauth_pswd_state = libssh2_NB_state_sent;
2401+ goto password_response;
2402+ }
2403+ }
2404+ } else {
2405+ libssh2_error(session, LIBSSH2_ERROR_PASSWORD_EXPIRED,
2406+ "Password Expired, and no callback specified",
2407+ 0);
2408+ session->userauth_pswd_state = libssh2_NB_state_idle;
2409+ return -1;
2410+ }
2411+ }
2412+ }
2413+
2414+ /* FAILURE */
2415+ LIBSSH2_FREE(session, session->userauth_pswd_data);
2416+ session->userauth_pswd_data = NULL;
2417+ session->userauth_pswd_state = libssh2_NB_state_idle;
2418+ return -1;
2419+}
2420+
2421+/* }}} */
2422+
2423+/* {{{ libssh2_file_read_publickey
2424+ * Read a public key from an id_???.pub style file
2425+ */
2426+static int
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)
2432+{
2433+ FILE *fd;
2434+ char c;
2435+ unsigned char *pubkey = NULL, *sp1, *sp2, *tmp;
2436+ size_t pubkey_len = 0;
2437+ unsigned int tmp_len;
2438+
2439+ _libssh2_debug(session, LIBSSH2_DBG_AUTH, "Loading public key file: %s",
2440+ pubkeyfile);
2441+ /* Read Public Key */
2442+ fd = fopen(pubkeyfile, "r");
2443+ if (!fd) {
2444+ libssh2_error(session, LIBSSH2_ERROR_FILE,
2445+ "Unable to open public key file", 0);
2446+ return -1;
2447+ }
2448+ while (!feof(fd) && (c = fgetc(fd)) != '\r' && c != '\n')
2449+ pubkey_len++;
2450+ if (feof(fd)) {
2451+ /* the last character was EOF */
2452+ pubkey_len--;
2453+ }
2454+ rewind(fd);
2455+
2456+ if (pubkey_len <= 1) {
2457+ libssh2_error(session, LIBSSH2_ERROR_FILE,
2458+ "Invalid data in public key file", 0);
2459+ fclose(fd);
2460+ return -1;
2461+ }
2462+
2463+ pubkey = LIBSSH2_ALLOC(session, pubkey_len);
2464+ if (!pubkey) {
2465+ libssh2_error(session, LIBSSH2_ERROR_ALLOC,
2466+ "Unable to allocate memory for public key data", 0);
2467+ fclose(fd);
2468+ return -1;
2469+ }
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);
2474+ fclose(fd);
2475+ return -1;
2476+ }
2477+ fclose(fd);
2478+ /*
2479+ * Remove trailing whitespace
2480+ */
2481+ while (pubkey_len && isspace(pubkey[pubkey_len - 1]))
2482+ pubkey_len--;
2483+
2484+ if (!pubkey_len) {
2485+ libssh2_error(session, LIBSSH2_ERROR_FILE, "Missing public key data",
2486+ 0);
2487+ LIBSSH2_FREE(session, pubkey);
2488+ return -1;
2489+ }
2490+
2491+ if ((sp1 = memchr(pubkey, ' ', pubkey_len)) == NULL) {
2492+ libssh2_error(session, LIBSSH2_ERROR_FILE, "Invalid public key data",
2493+ 0);
2494+ LIBSSH2_FREE(session, pubkey);
2495+ return -1;
2496+ }
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 */
2500+ *method = pubkey;
2501+ *method_len = sp1 - pubkey;
2502+
2503+ sp1++;
2504+
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;
2508+ }
2509+
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);
2515+ return -1;
2516+ }
2517+ *pubkeydata = tmp;
2518+ *pubkeydata_len = tmp_len;
2519+
2520+ return 0;
2521+}
2522+
2523+/* }}} */
2524+
2525+/* {{{ libssh2_file_read_privatekey
2526+ * Read a PEM encoded private key from an id_??? style file
2527+ */
2528+static int
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)
2534+{
2535+ const LIBSSH2_HOSTKEY_METHOD **hostkey_methods_avail =
2536+ libssh2_hostkey_methods();
2537+
2538+ _libssh2_debug(session, LIBSSH2_DBG_AUTH, "Loading private key file: %s",
2539+ privkeyfile);
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;
2547+ break;
2548+ }
2549+ hostkey_methods_avail++;
2550+ }
2551+ if (!*hostkey_method) {
2552+ libssh2_error(session, LIBSSH2_ERROR_METHOD_NONE,
2553+ "No handler for specified private key", 0);
2554+ return -1;
2555+ }
2556+
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);
2562+ return -1;
2563+ }
2564+
2565+ return 0;
2566+}
2567+
2568+/* }}} */
2569+
2570+/* {{{ libssh2_userauth_hostbased_fromfile_ex
2571+ * Authenticate using a keypair found in the named files
2572+ */
2573+LIBSSH2_API int
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)
2584+{
2585+ static const unsigned char reply_codes[3] =
2586+ { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 };
2587+ int rc;
2588+
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;
2594+ void *abstract;
2595+ unsigned char buf[5];
2596+ struct iovec datavec[4];
2597+
2598+ /* Zero the whole thing out */
2599+ memset(&session->userauth_host_packet_requirev_state, 0,
2600+ sizeof(session->userauth_host_packet_requirev_state));
2601+
2602+ if (libssh2_file_read_publickey
2603+ (session, &session->userauth_host_method,
2604+ &session->userauth_host_method_len, &pubkeydata, &pubkeydata_len,
2605+ publickey)) {
2606+ return -1;
2607+ }
2608+
2609+ /*
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)
2614+ */
2615+ session->userauth_host_packet_len =
2616+ username_len + session->userauth_host_method_len + hostname_len +
2617+ local_username_len + pubkeydata_len + 48;
2618+
2619+ /*
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
2623+ */
2624+ session->userauth_host_s = session->userauth_host_packet =
2625+ LIBSSH2_ALLOC(session,
2626+ session->userauth_host_packet_len + 4 + (4 +
2627+ session->
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;
2633+ return -1;
2634+ }
2635+
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;
2641+
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;
2646+
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;
2651+
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;
2658+
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;
2663+
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;
2668+
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;
2673+
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;
2681+ return -1;
2682+ }
2683+
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;
2691+
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);
2699+ }
2700+ return -1;
2701+ }
2702+
2703+ if (privkeyobj->dtor) {
2704+ privkeyobj->dtor(session, &abstract);
2705+ }
2706+
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 */
2711+ if (!newpacket) {
2712+ libssh2_error(session, LIBSSH2_ERROR_ALLOC,
2713+ "Failed allocating additional space for userauth-hostbased packet",
2714+ 0);
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;
2720+ return -1;
2721+ }
2722+ session->userauth_host_packet = newpacket;
2723+ }
2724+
2725+ session->userauth_host_s =
2726+ session->userauth_host_packet + session->userauth_host_packet_len;
2727+
2728+ libssh2_htonu32(session->userauth_host_s,
2729+ 4 + session->userauth_host_method_len + 4 + sig_len);
2730+ session->userauth_host_s += 4;
2731+
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;
2740+
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);
2746+
2747+ _libssh2_debug(session, LIBSSH2_DBG_AUTH,
2748+ "Attempting hostbased authentication");
2749+
2750+ session->userauth_host_state = libssh2_NB_state_created;
2751+ }
2752+
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;
2759+ } else if (rc) {
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;
2765+ return -1;
2766+ }
2767+ LIBSSH2_FREE(session, session->userauth_host_packet);
2768+ session->userauth_host_packet = NULL;
2769+
2770+ session->userauth_host_state = libssh2_NB_state_sent;
2771+ }
2772+
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,
2778+ &session->
2779+ userauth_host_packet_requirev_state);
2780+ if (rc == PACKET_EAGAIN) {
2781+ return PACKET_EAGAIN;
2782+ } else if (rc) {
2783+ session->userauth_host_state = libssh2_NB_state_idle;
2784+ return -1;
2785+ }
2786+
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;
2795+ return 0;
2796+ }
2797+ }
2798+
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",
2804+ 0);
2805+ session->userauth_host_state = libssh2_NB_state_idle;
2806+ return -1;
2807+}
2808+
2809+/* }}} */
2810+
2811+/* {{{ libssh2_userauth_publickey_fromfile_ex
2812+ * Authenticate using a keypair found in the named files
2813+ */
2814+LIBSSH2_API int
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)
2821+{
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
2826+ };
2827+ int rc;
2828+
2829+ if (session->userauth_pblc_state == libssh2_NB_state_idle) {
2830+ unsigned char *pubkeydata;
2831+
2832+ /* Zero the whole thing out */
2833+ memset(&session->userauth_pblc_packet_requirev_state, 0,
2834+ sizeof(session->userauth_pblc_packet_requirev_state));
2835+
2836+ if (libssh2_file_read_publickey
2837+ (session, &session->userauth_pblc_method,
2838+ &session->userauth_pblc_method_len, &pubkeydata, &pubkeydata_len,
2839+ publickey)) {
2840+ return -1;
2841+ }
2842+
2843+ /*
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)
2848+ */
2849+ session->userauth_pblc_packet_len =
2850+ username_len + session->userauth_pblc_method_len + pubkeydata_len +
2851+ 45;
2852+
2853+ /*
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
2857+ */
2858+ session->userauth_pblc_s = session->userauth_pblc_packet =
2859+ LIBSSH2_ALLOC(session,
2860+ session->userauth_pblc_packet_len + 4 + (4 +
2861+ session->
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);
2868+ return -1;
2869+ }
2870+
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;
2876+
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;
2881+
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;
2886+
2887+ session->userauth_pblc_b = session->userauth_pblc_s;
2888+ /* Not sending signature with *this* packet */
2889+ *(session->userauth_pblc_s++) = 0;
2890+
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;
2897+
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);
2903+
2904+ _libssh2_debug(session, LIBSSH2_DBG_AUTH,
2905+ "Attempting publickey authentication");
2906+
2907+ session->userauth_pblc_state = libssh2_NB_state_created;
2908+ }
2909+
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;
2915+ } else if (rc) {
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;
2923+ return -1;
2924+ }
2925+
2926+ session->userauth_pblc_state = libssh2_NB_state_sent;
2927+ }
2928+
2929+ if (session->userauth_pblc_state == libssh2_NB_state_sent) {
2930+ const LIBSSH2_HOSTKEY_METHOD *privkeyobj;
2931+ void *abstract;
2932+ unsigned char buf[5];
2933+ struct iovec datavec[4];
2934+ unsigned char *sig;
2935+ unsigned long sig_len;
2936+
2937+ rc = libssh2_packet_requirev_ex(session, reply_codes,
2938+ &session->userauth_pblc_data,
2939+ &session->userauth_pblc_data_len, 0,
2940+ NULL, 0,
2941+ &session->
2942+ userauth_pblc_packet_requirev_state);
2943+ if (rc == PACKET_EAGAIN) {
2944+ return PACKET_EAGAIN;
2945+ } else if (rc) {
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;
2951+ return -1;
2952+ }
2953+
2954+ if (session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
2955+ _libssh2_debug(session, LIBSSH2_DBG_AUTH,
2956+ "Pubkey authentication prematurely successful");
2957+ /*
2958+ * God help any SSH server that allows an UNVERIFIED
2959+ * public key to validate the user
2960+ */
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;
2969+ return 0;
2970+ }
2971+
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;
2983+ return -1;
2984+ }
2985+
2986+ /* Semi-Success! */
2987+ LIBSSH2_FREE(session, session->userauth_pblc_data);
2988+ session->userauth_pblc_data = NULL;
2989+
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;
2998+ return -1;
2999+ }
3000+
3001+ *session->userauth_pblc_b = 0x01;
3002+
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;
3010+
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);
3018+ }
3019+ session->userauth_pblc_state = libssh2_NB_state_idle;
3020+ return -1;
3021+ }
3022+
3023+ if (privkeyobj->dtor) {
3024+ privkeyobj->dtor(session, &abstract);
3025+ }
3026+
3027+ /*
3028+ * If this function was restarted, pubkeydata_len might still be 0
3029+ * which will cause an unnecessary but harmless realloc here.
3030+ */
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 */
3035+ if (!newpacket) {
3036+ libssh2_error(session, LIBSSH2_ERROR_ALLOC,
3037+ "Failed allocating additional space for userauth-publickey packet",
3038+ 0);
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;
3045+ return -1;
3046+ }
3047+ session->userauth_pblc_packet = newpacket;
3048+ }
3049+
3050+ session->userauth_pblc_s =
3051+ session->userauth_pblc_packet + session->userauth_pblc_packet_len;
3052+ session->userauth_pblc_b = NULL;
3053+
3054+ libssh2_htonu32(session->userauth_pblc_s,
3055+ 4 + session->userauth_pblc_method_len + 4 + sig_len);
3056+ session->userauth_pblc_s += 4;
3057+
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;
3066+
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);
3072+
3073+ _libssh2_debug(session, LIBSSH2_DBG_AUTH,
3074+ "Attempting publickey authentication -- phase 2");
3075+
3076+ session->userauth_pblc_state = libssh2_NB_state_sent1;
3077+ }
3078+
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;
3085+ } else if (rc) {
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;
3091+ return -1;
3092+ }
3093+ LIBSSH2_FREE(session, session->userauth_pblc_packet);
3094+ session->userauth_pblc_packet = NULL;
3095+
3096+ session->userauth_pblc_state = libssh2_NB_state_sent2;
3097+ }
3098+
3099+ /* PK_OK is no longer valid */
3100+ reply_codes[2] = 0;
3101+
3102+ rc = libssh2_packet_requirev_ex(session, reply_codes,
3103+ &session->userauth_pblc_data,
3104+ &session->userauth_pblc_data_len, 0, NULL,
3105+ 0,
3106+ &session->
3107+ userauth_pblc_packet_requirev_state);
3108+ if (rc == PACKET_EAGAIN) {
3109+ return PACKET_EAGAIN;
3110+ } else if (rc) {
3111+ session->userauth_pblc_state = libssh2_NB_state_idle;
3112+ return -1;
3113+ }
3114+
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;
3123+ return 0;
3124+ }
3125+
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",
3131+ 0);
3132+ session->userauth_pblc_state = libssh2_NB_state_idle;
3133+ return -1;
3134+}
3135+
3136+/* }}} */
3137+
3138+/* {{{ libssh2_userauth_keyboard_interactive
3139+ * Authenticate using a challenge-response authentication
3140+ */
3141+LIBSSH2_API int
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)))
3146+{
3147+ unsigned char *s;
3148+ int rc;
3149+
3150+ static const unsigned char reply_codes[4] = { SSH_MSG_USERAUTH_SUCCESS,
3151+ SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_INFO_REQUEST, 0
3152+ };
3153+ unsigned int language_tag_len;
3154+ unsigned int i;
3155+
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;
3163+
3164+ /* Zero the whole thing out */
3165+ memset(&session->userauth_kybd_packet_requirev_state, 0,
3166+ sizeof(session->userauth_kybd_packet_requirev_state));
3167+
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) */
3174+ ;
3175+
3176+ session->userauth_kybd_data = s =
3177+ LIBSSH2_ALLOC(session, session->userauth_kybd_packet_len);
3178+ if (!s) {
3179+ libssh2_error(session, LIBSSH2_ERROR_ALLOC,
3180+ "Unable to allocate memory for keyboard-interactive authentication",
3181+ 0);
3182+ return -1;
3183+ }
3184+
3185+ *s++ = SSH_MSG_USERAUTH_REQUEST;
3186+
3187+ /* user name */
3188+ libssh2_htonu32(s, username_len);
3189+ s += 4;
3190+ memcpy(s, username, username_len);
3191+ s += username_len;
3192+
3193+ /* service name */
3194+ libssh2_htonu32(s, sizeof("ssh-connection") - 1);
3195+ s += 4;
3196+ memcpy(s, "ssh-connection", sizeof("ssh-connection") - 1);
3197+ s += sizeof("ssh-connection") - 1;
3198+
3199+ /* "keyboard-interactive" */
3200+ libssh2_htonu32(s, sizeof("keyboard-interactive") - 1);
3201+ s += 4;
3202+ memcpy(s, "keyboard-interactive", sizeof("keyboard-interactive") - 1);
3203+ s += sizeof("keyboard-interactive") - 1;
3204+
3205+ /* language tag */
3206+ libssh2_htonu32(s, 0);
3207+ s += 4;
3208+
3209+ /* submethods */
3210+ libssh2_htonu32(s, 0);
3211+ s += 4;
3212+
3213+ _libssh2_debug(session, LIBSSH2_DBG_AUTH,
3214+ "Attempting keyboard-interactive authentication");
3215+
3216+ session->userauth_kybd_state = libssh2_NB_state_created;
3217+ }
3218+
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;
3224+ } else if (rc) {
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;
3230+ return -1;
3231+ }
3232+ LIBSSH2_FREE(session, session->userauth_kybd_data);
3233+ session->userauth_kybd_data = NULL;
3234+
3235+ session->userauth_kybd_state = libssh2_NB_state_sent;
3236+ }
3237+
3238+ for(;;) {
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,
3243+ 0, NULL, 0,
3244+ &session->
3245+ userauth_kybd_packet_requirev_state);
3246+ if (rc == PACKET_EAGAIN) {
3247+ return PACKET_EAGAIN;
3248+ } else if (rc) {
3249+ session->userauth_kybd_state = libssh2_NB_state_idle;
3250+ return -1;
3251+ }
3252+
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;
3260+ return 0;
3261+ }
3262+
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;
3267+ return -1;
3268+ }
3269+
3270+ /* server requested PAM-like conversation */
3271+
3272+ s = session->userauth_kybd_data + 1;
3273+
3274+ /* string name (ISO-10646 UTF-8) */
3275+ session->userauth_kybd_auth_name_len = libssh2_ntohu32(s);
3276+ s += 4;
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",
3282+ 0);
3283+ goto cleanup;
3284+ }
3285+ memcpy(session->userauth_kybd_auth_name, s,
3286+ session->userauth_kybd_auth_name_len);
3287+ s += session->userauth_kybd_auth_name_len;
3288+
3289+ /* string instruction (ISO-10646 UTF-8) */
3290+ session->userauth_kybd_auth_instruction_len = libssh2_ntohu32(s);
3291+ s += 4;
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",
3298+ 0);
3299+ goto cleanup;
3300+ }
3301+ memcpy(session->userauth_kybd_auth_instruction, s,
3302+ session->userauth_kybd_auth_instruction_len);
3303+ s += session->userauth_kybd_auth_instruction_len;
3304+
3305+ /* string language tag (as defined in [RFC-3066]) */
3306+ language_tag_len = libssh2_ntohu32(s);
3307+ s += 4;
3308+ /* ignoring this field as deprecated */
3309+ s += language_tag_len;
3310+
3311+ /* int num-prompts */
3312+ session->userauth_kybd_num_prompts = libssh2_ntohu32(s);
3313+ s += 4;
3314+
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",
3322+ 0);
3323+ goto cleanup;
3324+ }
3325+ memset(session->userauth_kybd_prompts, 0,
3326+ sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) *
3327+ session->userauth_kybd_num_prompts);
3328+
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",
3336+ 0);
3337+ goto cleanup;
3338+ }
3339+ memset(session->userauth_kybd_responses, 0,
3340+ sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) *
3341+ session->userauth_kybd_num_prompts);
3342+
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);
3346+ s += 4;
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",
3353+ 0);
3354+ goto cleanup;
3355+ }
3356+ memcpy(session->userauth_kybd_prompts[i].text, s,
3357+ session->userauth_kybd_prompts[i].length);
3358+ s += session->userauth_kybd_prompts[i].length;
3359+
3360+ /* boolean echo[1] */
3361+ session->userauth_kybd_prompts[i].echo = *s++;
3362+ }
3363+
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);
3372+
3373+ _libssh2_debug(session, LIBSSH2_DBG_AUTH,
3374+ "Keyboard-interactive response callback function invoked");
3375+
3376+ session->userauth_kybd_packet_len = 1 /* byte SSH_MSG_USERAUTH_INFO_RESPONSE */
3377+ + 4 /* int num-responses */
3378+ ;
3379+
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;
3384+ }
3385+
3386+ session->userauth_kybd_data = s =
3387+ LIBSSH2_ALLOC(session, session->userauth_kybd_packet_len);
3388+ if (!s) {
3389+ libssh2_error(session, LIBSSH2_ERROR_ALLOC,
3390+ "Unable to allocate memory for keyboard-interactive response packet",
3391+ 0);
3392+ goto cleanup;
3393+ }
3394+
3395+ *s = SSH_MSG_USERAUTH_INFO_RESPONSE;
3396+ s++;
3397+ libssh2_htonu32(s, session->userauth_kybd_num_prompts);
3398+ s += 4;
3399+
3400+ for(i = 0; i != session->userauth_kybd_num_prompts; ++i) {
3401+ libssh2_htonu32(s, session->userauth_kybd_responses[i].length);
3402+ s += 4;
3403+ memcpy(s, session->userauth_kybd_responses[i].text,
3404+ session->userauth_kybd_responses[i].length);
3405+ s += session->userauth_kybd_responses[i].length;
3406+ }
3407+
3408+ session->userauth_kybd_state = libssh2_NB_state_sent1;
3409+ }
3410+
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;
3416+ }
3417+ if (rc) {
3418+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
3419+ "Unable to send userauth-keyboard-interactive request",
3420+ 0);
3421+ goto cleanup;
3422+ }
3423+
3424+ session->userauth_kybd_auth_failure = 0;
3425+ }
3426+
3427+ cleanup:
3428+ /*
3429+ * It's safe to clean all the data here, because unallocated pointers
3430+ * are filled by zeroes
3431+ */
3432+
3433+ LIBSSH2_FREE(session, session->userauth_kybd_data);
3434+ session->userauth_kybd_data = NULL;
3435+
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;
3440+ }
3441+ }
3442+
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;
3448+ }
3449+ }
3450+
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;
3455+
3456+ if (session->userauth_kybd_auth_failure) {
3457+ session->userauth_kybd_state = libssh2_NB_state_idle;
3458+ return -1;
3459+ }
3460+
3461+ session->userauth_kybd_state = libssh2_NB_state_sent;
3462+ }
3463+}
3464+
3465+/* }}} */
3466
3467Property changes on: libssh2/src/userauth.c
3468___________________________________________________________________
3469Added: svn:mime-type
3470 + text/x-c
3471Added: svn:keywords
3472 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
3473Added: cvs2svn:cvs-rev
3474 + 1.2
3475Added: svn:eol-style
3476 + native
3477
3478Index: libssh2/src/mac.c
3479===================================================================
3480--- libssh2/src/mac.c (.../tags/RELEASE_0_11_0)
3481+++ libssh2/src/mac.c (.../trunk)
3482@@ -0,0 +1,311 @@
3483+/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
3484+ * All rights reserved.
3485+ *
3486+ * Redistribution and use in source and binary forms,
3487+ * with or without modification, are permitted provided
3488+ * that the following conditions are met:
3489+ *
3490+ * Redistributions of source code must retain the above
3491+ * copyright notice, this list of conditions and the
3492+ * following disclaimer.
3493+ *
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.
3498+ *
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.
3503+ *
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
3517+ * OF SUCH DAMAGE.
3518+ */
3519+
3520+#include "libssh2_priv.h"
3521+
3522+#ifdef LIBSSH2_MAC_NONE
3523+/* {{{ libssh2_mac_none_MAC
3524+ * Minimalist MAC: No MAC
3525+ */
3526+static int
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)
3531+{
3532+ return 0;
3533+}
3534+
3535+/* }}} */
3536+
3537+
3538+static LIBSSH2_MAC_METHOD libssh2_mac_method_none = {
3539+ "none",
3540+ 0,
3541+ 0,
3542+ NULL,
3543+ libssh2_mac_none_MAC,
3544+ NULL
3545+};
3546+#endif /* LIBSSH2_MAC_NONE */
3547+
3548+/* {{{ libssh2_mac_method_common_init
3549+ * Initialize simple mac methods
3550+ */
3551+static int
3552+libssh2_mac_method_common_init(LIBSSH2_SESSION * session, unsigned char *key,
3553+ int *free_key, void **abstract)
3554+{
3555+ *abstract = key;
3556+ *free_key = 0;
3557+ (void) session;
3558+
3559+ return 0;
3560+}
3561+
3562+/* }}} */
3563+
3564+/* {{{ libssh2_mac_method_common_dtor
3565+ * Cleanup simple mac methods
3566+ */
3567+static int
3568+libssh2_mac_method_common_dtor(LIBSSH2_SESSION * session, void **abstract)
3569+{
3570+ if (*abstract) {
3571+ LIBSSH2_FREE(session, *abstract);
3572+ }
3573+ *abstract = NULL;
3574+
3575+ return 0;
3576+}
3577+
3578+/* }}} */
3579+
3580+/* {{{ libssh2_mac_method_hmac_sha1_hash
3581+ * Calculate hash using full sha1 value
3582+ */
3583+static int
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)
3590+{
3591+ libssh2_hmac_ctx ctx;
3592+ unsigned char seqno_buf[4];
3593+ (void) session;
3594+
3595+ libssh2_htonu32(seqno_buf, seqno);
3596+
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);
3602+ }
3603+ libssh2_hmac_final(ctx, buf);
3604+ libssh2_hmac_cleanup(&ctx);
3605+
3606+ return 0;
3607+}
3608+
3609+/* }}} */
3610+
3611+static const LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_sha1 = {
3612+ "hmac-sha1",
3613+ 20,
3614+ 20,
3615+ libssh2_mac_method_common_init,
3616+ libssh2_mac_method_hmac_sha1_hash,
3617+ libssh2_mac_method_common_dtor,
3618+};
3619+
3620+/* {{{ libssh2_mac_method_hmac_sha1_96_hash
3621+ * Calculate hash using first 96 bits of sha1 value
3622+ */
3623+static int
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)
3630+{
3631+ unsigned char temp[SHA_DIGEST_LENGTH];
3632+
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);
3636+
3637+ return 0;
3638+}
3639+
3640+/* }}} */
3641+
3642+static const LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_sha1_96 = {
3643+ "hmac-sha1-96",
3644+ 12,
3645+ 20,
3646+ libssh2_mac_method_common_init,
3647+ libssh2_mac_method_hmac_sha1_96_hash,
3648+ libssh2_mac_method_common_dtor,
3649+};
3650+
3651+/* {{{ libssh2_mac_method_hmac_md5_hash
3652+ * Calculate hash using full md5 value
3653+ */
3654+static int
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)
3661+{
3662+ libssh2_hmac_ctx ctx;
3663+ unsigned char seqno_buf[4];
3664+ (void) session;
3665+
3666+ libssh2_htonu32(seqno_buf, seqno);
3667+
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);
3673+ }
3674+ libssh2_hmac_final(ctx, buf);
3675+ libssh2_hmac_cleanup(&ctx);
3676+
3677+ return 0;
3678+}
3679+
3680+/* }}} */
3681+
3682+static const LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_md5 = {
3683+ "hmac-md5",
3684+ 16,
3685+ 16,
3686+ libssh2_mac_method_common_init,
3687+ libssh2_mac_method_hmac_md5_hash,
3688+ libssh2_mac_method_common_dtor,
3689+};
3690+
3691+/* {{{ libssh2_mac_method_hmac_md5_96_hash
3692+ * Calculate hash using first 96 bits of md5 value
3693+ */
3694+static int
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)
3701+{
3702+ unsigned char temp[MD5_DIGEST_LENGTH];
3703+
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);
3707+
3708+ return 0;
3709+}
3710+
3711+/* }}} */
3712+
3713+static const LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_md5_96 = {
3714+ "hmac-md5-96",
3715+ 12,
3716+ 16,
3717+ libssh2_mac_method_common_init,
3718+ libssh2_mac_method_hmac_md5_96_hash,
3719+ libssh2_mac_method_common_dtor,
3720+};
3721+
3722+#if LIBSSH2_HMAC_RIPEMD
3723+/* {{{ libssh2_mac_method_hmac_ripemd160_hash
3724+ * Calculate hash using ripemd160 value
3725+ */
3726+static int
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,
3733+ void **abstract)
3734+{
3735+ libssh2_hmac_ctx ctx;
3736+ unsigned char seqno_buf[4];
3737+ (void) session;
3738+
3739+ libssh2_htonu32(seqno_buf, seqno);
3740+
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);
3746+ }
3747+ libssh2_hmac_final(ctx, buf);
3748+ libssh2_hmac_cleanup(&ctx);
3749+
3750+ return 0;
3751+}
3752+
3753+/* }}} */
3754+
3755+static const LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_ripemd160 = {
3756+ "hmac-ripemd160",
3757+ 20,
3758+ 20,
3759+ libssh2_mac_method_common_init,
3760+ libssh2_mac_method_hmac_ripemd160_hash,
3761+ libssh2_mac_method_common_dtor,
3762+};
3763+
3764+static const LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_ripemd160_openssh_com = {
3765+ "hmac-ripemd160@openssh.com",
3766+ 20,
3767+ 20,
3768+ libssh2_mac_method_common_init,
3769+ libssh2_mac_method_hmac_ripemd160_hash,
3770+ libssh2_mac_method_common_dtor,
3771+};
3772+#endif /* LIBSSH2_HMAC_RIPEMD */
3773+
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 */
3786+ NULL
3787+};
3788+
3789+const LIBSSH2_MAC_METHOD **
3790+libssh2_mac_methods(void)
3791+{
3792+ return _libssh2_mac_methods;
3793+}
3794
3795Property changes on: libssh2/src/mac.c
3796___________________________________________________________________
3797Added: svn:mime-type
3798 + text/x-c
3799Added: svn:keywords
3800 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
3801Added: cvs2svn:cvs-rev
3802 + 1.2
3803Added: svn:eol-style
3804 + native
3805
3806Index: libssh2/src/crypt.c
3807===================================================================
3808--- libssh2/src/crypt.c (.../tags/RELEASE_0_11_0)
3809+++ libssh2/src/crypt.c (.../trunk)
3810@@ -0,0 +1,256 @@
3811+/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
3812+ * All rights reserved.
3813+ *
3814+ * Redistribution and use in source and binary forms,
3815+ * with or without modification, are permitted provided
3816+ * that the following conditions are met:
3817+ *
3818+ * Redistributions of source code must retain the above
3819+ * copyright notice, this list of conditions and the
3820+ * following disclaimer.
3821+ *
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.
3826+ *
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.
3831+ *
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
3845+ * OF SUCH DAMAGE.
3846+ */
3847+
3848+#include "libssh2_priv.h"
3849+
3850+#ifdef LIBSSH2_CRYPT_NONE
3851+/* {{{ libssh2_crypt_none_crypt
3852+ * Minimalist cipher: VERY secure *wink*
3853+ */
3854+static int
3855+libssh2_crypt_none_crypt(LIBSSH2_SESSION * session, unsigned char *buf,
3856+ void **abstract)
3857+{
3858+ /* Do nothing to the data! */
3859+ return 0;
3860+}
3861+
3862+/* }}} */
3863+
3864+static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_none = {
3865+ "none",
3866+ 8, /* blocksize (SSH2 defines minimum blocksize as 8) */
3867+ 0, /* iv_len */
3868+ 0, /* secret_len */
3869+ 0, /* flags */
3870+ NULL,
3871+ libssh2_crypt_none_crypt,
3872+ NULL
3873+};
3874+#endif /* LIBSSH2_CRYPT_NONE */
3875+
3876+struct crypt_ctx
3877+{
3878+ int encrypt;
3879+ _libssh2_cipher_type(algo);
3880+ _libssh2_cipher_ctx h;
3881+};
3882+
3883+static int
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)
3889+{
3890+ struct crypt_ctx *ctx = LIBSSH2_ALLOC(session,
3891+ sizeof(struct crypt_ctx));
3892+ if (!ctx) {
3893+ return -1;
3894+ }
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);
3899+ return -1;
3900+ }
3901+ *abstract = ctx;
3902+ *free_iv = 1;
3903+ *free_secret = 1;
3904+ return 0;
3905+}
3906+
3907+static int
3908+_libssh2_encrypt(LIBSSH2_SESSION * session, unsigned char *block,
3909+ void **abstract)
3910+{
3911+ struct crypt_ctx *cctx = *(struct crypt_ctx **) abstract;
3912+ (void) session;
3913+ return _libssh2_cipher_crypt(&cctx->h, cctx->algo, cctx->encrypt, block);
3914+}
3915+
3916+static int
3917+_libssh2_dtor(LIBSSH2_SESSION * session, void **abstract)
3918+{
3919+ struct crypt_ctx **cctx = (struct crypt_ctx **) abstract;
3920+ if (cctx && *cctx) {
3921+ _libssh2_cipher_dtor(&(*cctx)->h);
3922+ LIBSSH2_FREE(session, *cctx);
3923+ *abstract = NULL;
3924+ }
3925+ return 0;
3926+}
3927+
3928+#if LIBSSH2_AES
3929+static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes128_cbc = {
3930+ "aes128-cbc",
3931+ 16, /* blocksize */
3932+ 16, /* initial value length */
3933+ 16, /* secret length -- 16*8 == 128bit */
3934+ 0, /* flags */
3935+ &_libssh2_init,
3936+ &_libssh2_encrypt,
3937+ &_libssh2_dtor,
3938+ _libssh2_cipher_aes128
3939+};
3940+
3941+static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes192_cbc = {
3942+ "aes192-cbc",
3943+ 16, /* blocksize */
3944+ 16, /* initial value length */
3945+ 24, /* secret length -- 24*8 == 192bit */
3946+ 0, /* flags */
3947+ &_libssh2_init,
3948+ &_libssh2_encrypt,
3949+ &_libssh2_dtor,
3950+ _libssh2_cipher_aes192
3951+};
3952+
3953+static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes256_cbc = {
3954+ "aes256-cbc",
3955+ 16, /* blocksize */
3956+ 16, /* initial value length */
3957+ 32, /* secret length -- 32*8 == 256bit */
3958+ 0, /* flags */
3959+ &_libssh2_init,
3960+ &_libssh2_encrypt,
3961+ &_libssh2_dtor,
3962+ _libssh2_cipher_aes256
3963+};
3964+
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 */
3972+ 0, /* flags */
3973+ &_libssh2_init,
3974+ &_libssh2_encrypt,
3975+ &_libssh2_dtor,
3976+ _libssh2_cipher_aes256
3977+};
3978+#endif /* LIBSSH2_AES */
3979+
3980+#if LIBSSH2_BLOWFISH
3981+static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_blowfish_cbc = {
3982+ "blowfish-cbc",
3983+ 8, /* blocksize */
3984+ 8, /* initial value length */
3985+ 16, /* secret length */
3986+ 0, /* flags */
3987+ &_libssh2_init,
3988+ &_libssh2_encrypt,
3989+ &_libssh2_dtor,
3990+ _libssh2_cipher_blowfish
3991+};
3992+#endif /* LIBSSH2_BLOWFISH */
3993+
3994+#if LIBSSH2_RC4
3995+static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_arcfour = {
3996+ "arcfour",
3997+ 8, /* blocksize */
3998+ 8, /* initial value length */
3999+ 16, /* secret length */
4000+ 0, /* flags */
4001+ &_libssh2_init,
4002+ &_libssh2_encrypt,
4003+ &_libssh2_dtor,
4004+ _libssh2_cipher_arcfour
4005+};
4006+#endif /* LIBSSH2_RC4 */
4007+
4008+#if LIBSSH2_CAST
4009+static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_cast128_cbc = {
4010+ "cast128-cbc",
4011+ 8, /* blocksize */
4012+ 8, /* initial value length */
4013+ 16, /* secret length */
4014+ 0, /* flags */
4015+ &_libssh2_init,
4016+ &_libssh2_encrypt,
4017+ &_libssh2_dtor,
4018+ _libssh2_cipher_cast5
4019+};
4020+#endif /* LIBSSH2_CAST */
4021+
4022+#if LIBSSH2_3DES
4023+static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_3des_cbc = {
4024+ "3des-cbc",
4025+ 8, /* blocksize */
4026+ 8, /* initial value length */
4027+ 24, /* secret length */
4028+ 0, /* flags */
4029+ &_libssh2_init,
4030+ &_libssh2_encrypt,
4031+ &_libssh2_dtor,
4032+ _libssh2_cipher_3des
4033+};
4034+#endif
4035+
4036+static const LIBSSH2_CRYPT_METHOD *_libssh2_crypt_methods[] = {
4037+#if LIBSSH2_AES
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 */
4046+#if LIBSSH2_RC4
4047+ &libssh2_crypt_method_arcfour,
4048+#endif /* LIBSSH2_RC4 */
4049+#if LIBSSH2_CAST
4050+ &libssh2_crypt_method_cast128_cbc,
4051+#endif /* LIBSSH2_CAST */
4052+#if LIBSSH2_3DES
4053+ &libssh2_crypt_method_3des_cbc,
4054+#endif /* LIBSSH2_DES */
4055+#ifdef LIBSSH2_CRYPT_NONE
4056+ &libssh2_crypt_method_none,
4057+#endif
4058+ NULL
4059+};
4060+
4061+/* Expose to kex.c */
4062+const LIBSSH2_CRYPT_METHOD **
4063+libssh2_crypt_methods(void)
4064+{
4065+ return _libssh2_crypt_methods;
4066+}
4067
4068Property changes on: libssh2/src/crypt.c
4069___________________________________________________________________
4070Added: svn:mime-type
4071 + text/x-c
4072Added: svn:keywords
4073 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
4074Added: cvs2svn:cvs-rev
4075 + 1.2
4076Added: svn:eol-style
4077 + native
4078
4079Index: libssh2/src/libgcrypt.h
4080===================================================================
4081--- libssh2/src/libgcrypt.h (.../tags/RELEASE_0_11_0)
4082+++ libssh2/src/libgcrypt.h (.../trunk)
4083@@ -0,0 +1,187 @@
4084+/* Copyright (C) 2006, 2007, The Written Word, Inc.
4085+ * Copyright (C) 2008, Simon Josefsson
4086+ * All rights reserved.
4087+ *
4088+ * Redistribution and use in source and binary forms,
4089+ * with or without modification, are permitted provided
4090+ * that the following conditions are met:
4091+ *
4092+ * Redistributions of source code must retain the above
4093+ * copyright notice, this list of conditions and the
4094+ * following disclaimer.
4095+ *
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.
4100+ *
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.
4105+ *
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
4119+ * OF SUCH DAMAGE.
4120+ */
4121+
4122+#include <gcrypt.h>
4123+
4124+#define LIBSSH2_MD5 1
4125+
4126+#define LIBSSH2_HMAC_RIPEMD 1
4127+
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
4133+
4134+#define LIBSSH2_RSA 1
4135+#define LIBSSH2_DSA 1
4136+
4137+#define MD5_DIGEST_LENGTH 16
4138+#define SHA_DIGEST_LENGTH 20
4139+
4140+#define libssh2_random(buf, len) \
4141+ (gcry_randomize ((buf), (len), GCRY_STRONG_RANDOM), 1)
4142+
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)
4150+
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)
4158+
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);
4175+
4176+#define libssh2_crypto_init() gcry_control (GCRYCTL_DISABLE_SECMEM)
4177+
4178+#define libssh2_rsa_ctx struct gcry_sexp
4179+
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);
4209+
4210+#define _libssh2_rsa_free(rsactx) gcry_sexp_release (rsactx)
4211+
4212+#define libssh2_dsa_ctx struct gcry_sexp
4213+
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);
4233+
4234+#define _libssh2_dsa_free(dsactx) gcry_sexp_release (dsactx)
4235+
4236+#define _libssh2_cipher_type(name) int name
4237+#define _libssh2_cipher_ctx gcry_cipher_hd_t
4238+
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
4246+
4247+int _libssh2_cipher_init(_libssh2_cipher_ctx * h,
4248+ _libssh2_cipher_type(algo),
4249+ unsigned char *iv,
4250+ unsigned char *secret, int encrypt);
4251+
4252+int _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx,
4253+ _libssh2_cipher_type(algo),
4254+ int encrypt, unsigned char *block);
4255+
4256+#define _libssh2_cipher_dtor(ctx) gcry_cipher_close(*(ctx))
4257+
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)
4271
4272Property changes on: libssh2/src/libgcrypt.h
4273___________________________________________________________________
4274Added: svn:mime-type
4275 + text/x-c
4276Added: svn:keywords
4277 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
4278Added: cvs2svn:cvs-rev
4279 + 1.1
4280Added: svn:eol-style
4281 + native
4282Added: svn:executable
4283 + *
4284
4285Index: libssh2/src/packet.c
4286===================================================================
4287--- libssh2/src/packet.c (.../tags/RELEASE_0_11_0)
4288+++ libssh2/src/packet.c (.../trunk)
4289@@ -0,0 +1,1270 @@
4290+/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
4291+ * All rights reserved.
4292+ *
4293+ * Redistribution and use in source and binary forms,
4294+ * with or without modification, are permitted provided
4295+ * that the following conditions are met:
4296+ *
4297+ * Redistributions of source code must retain the above
4298+ * copyright notice, this list of conditions and the
4299+ * following disclaimer.
4300+ *
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.
4305+ *
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.
4310+ *
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
4324+ * OF SUCH DAMAGE.
4325+ */
4326+
4327+#include "libssh2_priv.h"
4328+#include <errno.h>
4329+#include <fcntl.h>
4330+
4331+#ifdef HAVE_UNISTD_H
4332+#include <unistd.h>
4333+#endif
4334+
4335+#ifdef HAVE_SYS_TIME_H
4336+#include <sys/time.h>
4337+#endif
4338+
4339+#ifdef HAVE_INTTYPES_H
4340+#include <inttypes.h>
4341+#endif
4342+
4343+/* Needed for struct iovec on some platforms */
4344+#ifdef HAVE_SYS_UIO_H
4345+#include <sys/uio.h>
4346+#endif
4347+
4348+#include <sys/types.h>
4349+
4350+/* {{{ libssh2_packet_queue_listener
4351+ * Queue a connection request for a listener
4352+ */
4353+static inline int
4354+libssh2_packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data,
4355+ unsigned long datalen,
4356+ packet_queue_listener_state_t * listen_state)
4357+{
4358+ /*
4359+ * Look for a matching listener
4360+ */
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);
4364+ unsigned char *p;
4365+ LIBSSH2_LISTENER *listen = session->listeners;
4366+ char failure_code = 1; /* SSH_OPEN_ADMINISTRATIVELY_PROHIBITED */
4367+ int rc;
4368+
4369+ (void) datalen;
4370+
4371+ if (listen_state->state == libssh2_NB_state_idle) {
4372+ listen_state->sender_channel = libssh2_ntohu32(s);
4373+ s += 4;
4374+
4375+ listen_state->initial_window_size = libssh2_ntohu32(s);
4376+ s += 4;
4377+ listen_state->packet_size = libssh2_ntohu32(s);
4378+ s += 4;
4379+
4380+ listen_state->host_len = libssh2_ntohu32(s);
4381+ s += 4;
4382+ listen_state->host = s;
4383+ s += listen_state->host_len;
4384+ listen_state->port = libssh2_ntohu32(s);
4385+ s += 4;
4386+
4387+ listen_state->shost_len = libssh2_ntohu32(s);
4388+ s += 4;
4389+ listen_state->shost = s;
4390+ s += listen_state->shost_len;
4391+ listen_state->sport = libssh2_ntohu32(s);
4392+ s += 4;
4393+
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);
4398+
4399+ listen_state->state = libssh2_NB_state_allocated;
4400+ }
4401+
4402+ if (listen_state->state != libssh2_NB_state_sent) {
4403+ while (listen) {
4404+ if ((listen->port == (int) listen_state->port) &&
4405+ (strlen(listen->host) == listen_state->host_len) &&
4406+ (memcmp
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;
4411+
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;
4421+ break;
4422+ }
4423+
4424+ channel = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL));
4425+ if (!channel) {
4426+ libssh2_error(session, LIBSSH2_ERROR_ALLOC,
4427+ "Unable to allocate a channel for new connection",
4428+ 0);
4429+ failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */
4430+ listen_state->state = libssh2_NB_state_sent;
4431+ break;
4432+ }
4433+ memset(channel, 0, sizeof(LIBSSH2_CHANNEL));
4434+
4435+ channel->session = session;
4436+ channel->channel_type_len = sizeof("forwarded-tcpip") - 1;
4437+ channel->channel_type = LIBSSH2_ALLOC(session,
4438+ channel->
4439+ channel_type_len +
4440+ 1);
4441+ if (!channel->channel_type) {
4442+ libssh2_error(session, LIBSSH2_ERROR_ALLOC,
4443+ "Unable to allocate a channel for new connection",
4444+ 0);
4445+ LIBSSH2_FREE(session, channel);
4446+ failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */
4447+ listen_state->state = libssh2_NB_state_sent;
4448+ break;
4449+ }
4450+ memcpy(channel->channel_type, "forwarded-tcpip",
4451+ channel->channel_type_len + 1);
4452+
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;
4460+
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;
4467+
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);
4475+
4476+ p = listen_state->packet;
4477+ *(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION;
4478+ libssh2_htonu32(p, channel->remote.id);
4479+ p += 4;
4480+ libssh2_htonu32(p, channel->local.id);
4481+ p += 4;
4482+ libssh2_htonu32(p, channel->remote.window_size_initial);
4483+ p += 4;
4484+ libssh2_htonu32(p, channel->remote.packet_size);
4485+ p += 4;
4486+
4487+ listen_state->state = libssh2_NB_state_created;
4488+ }
4489+
4490+ if (listen_state->state == libssh2_NB_state_created) {
4491+ rc = libssh2_packet_write(session, listen_state->packet,
4492+ 17);
4493+ if (rc == PACKET_EAGAIN) {
4494+ return PACKET_EAGAIN;
4495+ } else if (rc) {
4496+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
4497+ "Unable to send channel open confirmation",
4498+ 0);
4499+ listen_state->state = libssh2_NB_state_idle;
4500+ return -1;
4501+ }
4502+
4503+ /* Link the channel into the end of the queue list */
4504+
4505+ if (!last_queued) {
4506+ listen->queue = channel;
4507+ listen_state->state = libssh2_NB_state_idle;
4508+ return 0;
4509+ }
4510+
4511+ while (last_queued->next) {
4512+ last_queued = last_queued->next;
4513+ }
4514+
4515+ last_queued->next = channel;
4516+ channel->prev = last_queued;
4517+
4518+ listen->queue_size++;
4519+
4520+ listen_state->state = libssh2_NB_state_idle;
4521+ return 0;
4522+ }
4523+ }
4524+
4525+ listen = listen->next;
4526+ }
4527+
4528+ listen_state->state = libssh2_NB_state_sent;
4529+ }
4530+
4531+ /* We're not listening to you */
4532+ {
4533+ p = listen_state->packet;
4534+ *(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE;
4535+ libssh2_htonu32(p, listen_state->sender_channel);
4536+ p += 4;
4537+ libssh2_htonu32(p, failure_code);
4538+ p += 4;
4539+ libssh2_htonu32(p, sizeof(FwdNotReq) - 1);
4540+ p += 4;
4541+ memcpy(s, FwdNotReq, sizeof(FwdNotReq) - 1);
4542+ p += sizeof(FwdNotReq) - 1;
4543+ libssh2_htonu32(p, 0);
4544+
4545+ rc = libssh2_packet_write(session, listen_state->packet, packet_len);
4546+ if (rc == PACKET_EAGAIN) {
4547+ return PACKET_EAGAIN;
4548+ } else if (rc) {
4549+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
4550+ "Unable to send open failure", 0);
4551+ listen_state->state = libssh2_NB_state_idle;
4552+ return -1;
4553+ }
4554+ listen_state->state = libssh2_NB_state_idle;
4555+ return 0;
4556+ }
4557+}
4558+
4559+/* }}} */
4560+
4561+/* {{{ libssh2_packet_x11_open
4562+ * Accept a forwarded X11 connection
4563+ */
4564+static inline int
4565+libssh2_packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data,
4566+ unsigned long datalen,
4567+ packet_x11_open_state_t * x11open_state)
4568+{
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);
4573+ unsigned char *p;
4574+ LIBSSH2_CHANNEL *channel;
4575+ int rc;
4576+
4577+ (void) datalen;
4578+
4579+ if (x11open_state->state == libssh2_NB_state_idle) {
4580+ x11open_state->sender_channel = libssh2_ntohu32(s);
4581+ s += 4;
4582+ x11open_state->initial_window_size = libssh2_ntohu32(s);
4583+ s += 4;
4584+ x11open_state->packet_size = libssh2_ntohu32(s);
4585+ s += 4;
4586+ x11open_state->shost_len = libssh2_ntohu32(s);
4587+ s += 4;
4588+ x11open_state->shost = s;
4589+ s += x11open_state->shost_len;
4590+ x11open_state->sport = libssh2_ntohu32(s);
4591+ s += 4;
4592+
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);
4597+
4598+ x11open_state->state = libssh2_NB_state_allocated;
4599+ }
4600+
4601+ if (session->x11) {
4602+ if (x11open_state->state == libssh2_NB_state_allocated) {
4603+ channel = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL));
4604+ if (!channel) {
4605+ libssh2_error(session, LIBSSH2_ERROR_ALLOC,
4606+ "Unable to allocate a channel for new connection",
4607+ 0);
4608+ failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */
4609+ goto x11_exit;
4610+ }
4611+ memset(channel, 0, sizeof(LIBSSH2_CHANNEL));
4612+
4613+ channel->session = session;
4614+ channel->channel_type_len = sizeof("x11") - 1;
4615+ channel->channel_type = LIBSSH2_ALLOC(session,
4616+ channel->channel_type_len +
4617+ 1);
4618+ if (!channel->channel_type) {
4619+ libssh2_error(session, LIBSSH2_ERROR_ALLOC,
4620+ "Unable to allocate a channel for new connection",
4621+ 0);
4622+ LIBSSH2_FREE(session, channel);
4623+ failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */
4624+ goto x11_exit;
4625+ }
4626+ memcpy(channel->channel_type, "x11",
4627+ channel->channel_type_len + 1);
4628+
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;
4634+
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;
4640+
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);
4651+ p += 4;
4652+ libssh2_htonu32(p, channel->local.id);
4653+ p += 4;
4654+ libssh2_htonu32(p, channel->remote.window_size_initial);
4655+ p += 4;
4656+ libssh2_htonu32(p, channel->remote.packet_size);
4657+ p += 4;
4658+
4659+ x11open_state->state = libssh2_NB_state_created;
4660+ }
4661+
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;
4666+ } else if (rc) {
4667+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
4668+ "Unable to send channel open confirmation", 0);
4669+ x11open_state->state = libssh2_NB_state_idle;
4670+ return -1;
4671+ }
4672+
4673+ /* Link the channel into the session */
4674+ if (session->channels.tail) {
4675+ session->channels.tail->next = channel;
4676+ channel->prev = session->channels.tail;
4677+ } else {
4678+ session->channels.head = channel;
4679+ channel->prev = NULL;
4680+ }
4681+ channel->next = NULL;
4682+ session->channels.tail = channel;
4683+
4684+ /*
4685+ * Pass control to the callback, they may turn right around and
4686+ * free the channel, or actually use it
4687+ */
4688+ LIBSSH2_X11_OPEN(channel, (char *) x11open_state->shost,
4689+ x11open_state->sport);
4690+
4691+ x11open_state->state = libssh2_NB_state_idle;
4692+ return 0;
4693+ }
4694+ } else {
4695+ failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */
4696+ }
4697+
4698+ x11_exit:
4699+ p = x11open_state->packet;
4700+ *(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE;
4701+ libssh2_htonu32(p, x11open_state->sender_channel);
4702+ p += 4;
4703+ libssh2_htonu32(p, failure_code);
4704+ p += 4;
4705+ libssh2_htonu32(p, sizeof(X11FwdUnAvil) - 1);
4706+ p += 4;
4707+ memcpy(s, X11FwdUnAvil, sizeof(X11FwdUnAvil) - 1);
4708+ p += sizeof(X11FwdUnAvil) - 1;
4709+ libssh2_htonu32(p, 0);
4710+
4711+ rc = libssh2_packet_write(session, x11open_state->packet, packet_len);
4712+ if (rc == PACKET_EAGAIN) {
4713+ return PACKET_EAGAIN;
4714+ } else if (rc) {
4715+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
4716+ "Unable to send open failure", 0);
4717+ x11open_state->state = libssh2_NB_state_idle;
4718+ return -1;
4719+ }
4720+ x11open_state->state = libssh2_NB_state_idle;
4721+ return 0;
4722+}
4723+
4724+/* }}} */
4725+
4726+/* {{{ libssh2_packet_new
4727+ * Create a new packet and attach it to the brigade
4728+ */
4729+int
4730+libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
4731+ size_t datalen, int macstate)
4732+{
4733+ int rc;
4734+
4735+ if (session->packAdd_state == libssh2_NB_state_idle) {
4736+ session->packAdd_data_head = 0;
4737+
4738+ /* Zero the whole thing out */
4739+ memset(&session->packAdd_key_state, 0,
4740+ sizeof(session->packAdd_key_state));
4741+
4742+ /* Zero the whole thing out */
4743+ memset(&session->packAdd_Qlstn_state, 0,
4744+ sizeof(session->packAdd_Qlstn_state));
4745+
4746+ /* Zero the whole thing out */
4747+ memset(&session->packAdd_x11open_state, 0,
4748+ sizeof(session->packAdd_x11open_state));
4749+
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;
4758+ } else {
4759+ libssh2_error(session, LIBSSH2_ERROR_INVALID_MAC,
4760+ "Invalid Message Authentication Code received",
4761+ 0);
4762+ if (session->ssh_msg_disconnect) {
4763+ LIBSSH2_DISCONNECT(session, SSH_DISCONNECT_MAC_ERROR,
4764+ "Invalid MAC received",
4765+ sizeof("Invalid MAC received") - 1,
4766+ "", 0);
4767+ }
4768+ LIBSSH2_FREE(session, data);
4769+ return -1;
4770+ }
4771+ } else {
4772+ libssh2_error(session, LIBSSH2_ERROR_INVALID_MAC,
4773+ "Invalid Message Authentication Code received",
4774+ 0);
4775+ if (session->ssh_msg_disconnect) {
4776+ LIBSSH2_DISCONNECT(session, SSH_DISCONNECT_MAC_ERROR,
4777+ "Invalid MAC received",
4778+ sizeof("Invalid MAC received") - 1,
4779+ "", 0);
4780+ }
4781+ LIBSSH2_FREE(session, data);
4782+ return -1;
4783+ }
4784+ }
4785+
4786+ session->packAdd_state = libssh2_NB_state_allocated;
4787+ }
4788+
4789+ /*
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
4793+ */
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;
4800+ }
4801+
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:
4806+ {
4807+ char *message, *language;
4808+ int reason, message_len, language_len;
4809+
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);
4815+ /*
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,
4824+ * but it's "kind"
4825+ */
4826+ message[message_len] = '\0';
4827+ language = (char *) data + 9 + message_len + 3;
4828+ if (language_len) {
4829+ memcpy(language, language + 1, language_len);
4830+ }
4831+ language[language_len] = '\0';
4832+
4833+ if (session->ssh_msg_disconnect) {
4834+ LIBSSH2_DISCONNECT(session, reason, message,
4835+ message_len, language, language_len);
4836+ }
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;
4843+ return -1;
4844+ }
4845+ break;
4846+
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);
4853+ }
4854+ LIBSSH2_FREE(session, data);
4855+ session->packAdd_state = libssh2_NB_state_idle;
4856+ return 0;
4857+ break;
4858+
4859+ case SSH_MSG_DEBUG:
4860+ {
4861+ int always_display = data[0];
4862+ char *message, *language;
4863+ int message_len, language_len;
4864+
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);
4869+ /*
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,
4878+ * but it's "kind"
4879+ */
4880+ message[message_len] = '\0';
4881+ language = (char *) data + 6 + message_len + 3;
4882+ if (language_len) {
4883+ memcpy(language, language + 1, language_len);
4884+ }
4885+ language[language_len] = '\0';
4886+
4887+ if (session->ssh_msg_debug) {
4888+ LIBSSH2_DEBUG(session, always_display, message,
4889+ message_len, language, language_len);
4890+ }
4891+ /*
4892+ * _libssh2_debug will actually truncate this for us so
4893+ * that it's not an inordinate about of data
4894+ */
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;
4899+ return 0;
4900+ }
4901+ break;
4902+
4903+ case SSH_MSG_CHANNEL_EXTENDED_DATA:
4904+ /* streamid(4) */
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;
4909+ {
4910+ session->packAdd_channel = libssh2_channel_locate(session,
4911+ libssh2_ntohu32
4912+ (data + 1));
4913+
4914+ if (!session->packAdd_channel) {
4915+ libssh2_error(session, LIBSSH2_ERROR_CHANNEL_UNKNOWN,
4916+ "Packet received for unknown channel, ignoring",
4917+ 0);
4918+ LIBSSH2_FREE(session, data);
4919+ session->packAdd_state = libssh2_NB_state_idle;
4920+ return 0;
4921+ }
4922+#ifdef LIBSSH2DEBUG
4923+ {
4924+ unsigned long stream_id = 0;
4925+
4926+ if (data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) {
4927+ stream_id = libssh2_ntohu32(data + 5);
4928+ }
4929+
4930+ _libssh2_debug(session, LIBSSH2_DBG_CONN,
4931+ "%d bytes received for channel %lu/%lu stream #%lu",
4932+ (int) (datalen -
4933+ session->packAdd_data_head),
4934+ session->packAdd_channel->local.id,
4935+ session->packAdd_channel->remote.id,
4936+ stream_id);
4937+ }
4938+#endif
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);
4945+
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->
4953+ packAdd_channel,
4954+ datalen - 13,
4955+ 0);
4956+ if (rc == PACKET_EAGAIN) {
4957+ session->socket_block_directions =
4958+ LIBSSH2_SESSION_BLOCK_OUTBOUND;
4959+ return PACKET_EAGAIN;
4960+ }
4961+ session->packAdd_state = libssh2_NB_state_idle;
4962+ return 0;
4963+ }
4964+
4965+ /*
4966+ * REMEMBER! remote means remote as source of data,
4967+ * NOT remote window!
4968+ */
4969+ if (session->packAdd_channel->remote.packet_size <
4970+ (datalen - session->packAdd_data_head)) {
4971+ /*
4972+ * Spec says we MAY ignore bytes sent beyond
4973+ * packet_size
4974+ */
4975+ libssh2_error(session,
4976+ LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED,
4977+ "Packet contains more data than we offered to receive, truncating",
4978+ 0);
4979+ datalen =
4980+ session->packAdd_channel->remote.packet_size +
4981+ session->packAdd_data_head;
4982+ }
4983+ if (session->packAdd_channel->remote.window_size <= 0) {
4984+ /*
4985+ * Spec says we MAY ignore bytes sent beyond
4986+ * window_size
4987+ */
4988+ libssh2_error(session,
4989+ LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED,
4990+ "The current receive window is full, data ignored",
4991+ 0);
4992+ LIBSSH2_FREE(session, data);
4993+ session->packAdd_state = libssh2_NB_state_idle;
4994+ return 0;
4995+ }
4996+ /* Reset EOF status */
4997+ session->packAdd_channel->remote.eof = 0;
4998+
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",
5004+ 0);
5005+ datalen =
5006+ session->packAdd_channel->remote.window_size +
5007+ session->packAdd_data_head;
5008+ } else {
5009+ /* Now that we've received it, shrink our window */
5010+ session->packAdd_channel->remote.window_size -=
5011+ datalen - session->packAdd_data_head;
5012+ }
5013+ }
5014+ break;
5015+
5016+ case SSH_MSG_CHANNEL_EOF:
5017+ {
5018+ session->packAdd_channel = libssh2_channel_locate(session,
5019+ libssh2_ntohu32
5020+ (data + 1));
5021+
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;
5026+ return 0;
5027+ }
5028+
5029+ _libssh2_debug(session,
5030+ LIBSSH2_DBG_CONN,
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;
5035+
5036+ LIBSSH2_FREE(session, data);
5037+ session->packAdd_state = libssh2_NB_state_idle;
5038+ return 0;
5039+ }
5040+ break;
5041+
5042+ case SSH_MSG_CHANNEL_REQUEST:
5043+ {
5044+ if (libssh2_ntohu32(data + 5) == sizeof("exit-status") - 1
5045+ && !memcmp("exit-status", data + 9,
5046+ sizeof("exit-status") - 1)) {
5047+
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));
5052+
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);
5061+ }
5062+
5063+ LIBSSH2_FREE(session, data);
5064+ session->packAdd_state = libssh2_NB_state_idle;
5065+ return 0;
5066+ }
5067+ }
5068+ break;
5069+
5070+ case SSH_MSG_CHANNEL_CLOSE:
5071+ {
5072+ session->packAdd_channel = libssh2_channel_locate(session,
5073+ libssh2_ntohu32
5074+ (data + 1));
5075+
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;
5080+ return 0;
5081+ }
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);
5086+
5087+ session->packAdd_channel->remote.close = 1;
5088+ session->packAdd_channel->remote.eof = 1;
5089+ /* TODO: Add a callback for this */
5090+
5091+ LIBSSH2_FREE(session, data);
5092+ session->packAdd_state = libssh2_NB_state_idle;
5093+ return 0;
5094+ }
5095+ break;
5096+
5097+ case SSH_MSG_CHANNEL_OPEN:
5098+ if ((datalen >= (sizeof("forwarded-tcpip") + 4)) &&
5099+ ((sizeof("forwarded-tcpip") - 1) == libssh2_ntohu32(data + 1))
5100+ &&
5101+ (memcmp
5102+ (data + 5, "forwarded-tcpip",
5103+ sizeof("forwarded-tcpip") - 1) == 0)) {
5104+
5105+ libssh2_packet_add_jump_point2:
5106+ session->packAdd_state = libssh2_NB_state_jump2;
5107+ rc = libssh2_packet_queue_listener(session, data, datalen,
5108+ &session->
5109+ packAdd_Qlstn_state);
5110+ if (rc == PACKET_EAGAIN) {
5111+ session->socket_block_directions =
5112+ LIBSSH2_SESSION_BLOCK_OUTBOUND;
5113+ return PACKET_EAGAIN;
5114+ }
5115+
5116+ LIBSSH2_FREE(session, data);
5117+ session->packAdd_state = libssh2_NB_state_idle;
5118+ return rc;
5119+ }
5120+ if ((datalen >= (sizeof("x11") + 4)) &&
5121+ ((sizeof("x11") - 1) == libssh2_ntohu32(data + 1)) &&
5122+ (memcmp(data + 5, "x11", sizeof("x11") - 1) == 0)) {
5123+
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;
5132+ }
5133+
5134+ LIBSSH2_FREE(session, data);
5135+ session->packAdd_state = libssh2_NB_state_idle;
5136+ return rc;
5137+ }
5138+ break;
5139+
5140+ case SSH_MSG_CHANNEL_WINDOW_ADJUST:
5141+ {
5142+ unsigned long bytestoadd = libssh2_ntohu32(data + 5);
5143+ session->packAdd_channel = libssh2_channel_locate(session,
5144+ libssh2_ntohu32
5145+ (data + 1));
5146+
5147+ if (session->packAdd_channel && bytestoadd) {
5148+ session->packAdd_channel->local.window_size += bytestoadd;
5149+ }
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,
5154+ bytestoadd,
5155+ session->packAdd_channel->local.window_size);
5156+
5157+ LIBSSH2_FREE(session, data);
5158+ session->packAdd_state = libssh2_NB_state_idle;
5159+ return 0;
5160+ }
5161+ break;
5162+ }
5163+
5164+ session->packAdd_state = libssh2_NB_state_sent;
5165+ }
5166+
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;
5175+ return -1;
5176+ }
5177+ memset(session->packAdd_packet, 0, sizeof(LIBSSH2_PACKET));
5178+
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;
5185+
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;
5190+ } else {
5191+ session->packets.head = session->packAdd_packet;
5192+ session->packets.tail = session->packAdd_packet;
5193+ session->packAdd_packet->prev = NULL;
5194+ }
5195+
5196+ session->packAdd_state = libssh2_NB_state_sent1;
5197+ }
5198+
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) {
5203+ /*
5204+ * Remote wants new keys
5205+ * Well, it's already in the brigade,
5206+ * let's just call back into ourselves
5207+ */
5208+ _libssh2_debug(session, LIBSSH2_DBG_TRANS, "Renegotiating Keys");
5209+
5210+ session->packAdd_state = libssh2_NB_state_sent2;
5211+ }
5212+
5213+ /*
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
5218+ * conversation.
5219+ */
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;
5224+
5225+ /*
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?
5229+ */
5230+ memset(&session->startup_key_state, 0, sizeof(key_exchange_state_t));
5231+
5232+ /*
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
5235+ */
5236+ rc = libssh2_kex_exchange(session, 1, &session->startup_key_state);
5237+ if (rc == PACKET_EAGAIN) {
5238+ return PACKET_EAGAIN;
5239+ }
5240+ }
5241+
5242+ session->packAdd_state = libssh2_NB_state_idle;
5243+ return 0;
5244+}
5245+
5246+/* }}} */
5247+
5248+/* {{{ libssh2_packet_ask
5249+ * Scan the brigade for a matching packet type, optionally poll the socket for
5250+ * a packet first
5251+ */
5252+int
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)
5257+{
5258+ LIBSSH2_PACKET *packet = session->packets.head;
5259+
5260+ if (poll_socket) {
5261+ /*
5262+ * XXX CHECK ***
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()
5266+ */
5267+ libssh2pack_t rc = libssh2_packet_read(session);
5268+ if ((rc < 0) && !packet) {
5269+ return rc;
5270+ }
5271+ }
5272+ _libssh2_debug(session, LIBSSH2_DBG_TRANS,
5273+ "Looking for packet of type: %d", (int) packet_type);
5274+
5275+ while (packet) {
5276+ if (packet->data[0] == packet_type
5277+ && (packet->data_len >= (match_ofs + match_len)) && (!match_buf
5278+ ||
5279+ (memcmp
5280+ (packet->
5281+ data +
5282+ match_ofs,
5283+ match_buf,
5284+ match_len)
5285+ == 0))) {
5286+ *data = packet->data;
5287+ *data_len = packet->data_len;
5288+
5289+ if (packet->prev) {
5290+ packet->prev->next = packet->next;
5291+ } else {
5292+ session->packets.head = packet->next;
5293+ }
5294+
5295+ if (packet->next) {
5296+ packet->next->prev = packet->prev;
5297+ } else {
5298+ session->packets.tail = packet->prev;
5299+ }
5300+
5301+ LIBSSH2_FREE(session, packet);
5302+
5303+ return 0;
5304+ }
5305+ packet = packet->next;
5306+ }
5307+ return -1;
5308+}
5309+
5310+/* }}} */
5311+
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
5315+ */
5316+int
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)
5323+{
5324+ int i, packet_types_len = strlen((char *) packet_types);
5325+
5326+ for(i = 0; i < packet_types_len; i++) {
5327+ /*
5328+ * XXX CHECK XXX
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.
5332+ */
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)) {
5336+ return 0;
5337+ }
5338+ }
5339+
5340+ return -1;
5341+}
5342+
5343+/* }}} */
5344+
5345+/* {{{ waitsocket
5346+ * Returns
5347+ * negative on error
5348+ * >0 on incoming data
5349+ * 0 on timeout
5350+ *
5351+ * FIXME: convert to use poll on systems that have it.
5352+ */
5353+int
5354+libssh2_waitsocket(LIBSSH2_SESSION * session, long seconds)
5355+{
5356+ struct timeval timeout;
5357+ int rc;
5358+ fd_set fd;
5359+
5360+ timeout.tv_sec = seconds;
5361+ timeout.tv_usec = 0;
5362+
5363+ FD_ZERO(&fd);
5364+
5365+ FD_SET(session->socket_fd, &fd);
5366+
5367+ rc = select(session->socket_fd + 1, &fd, NULL, NULL, &timeout);
5368+
5369+ return rc;
5370+}
5371+
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
5375+ *
5376+ * Returns negative on error
5377+ * Returns 0 when it has taken care of the requested packet.
5378+ */
5379+int
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)
5386+{
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 */
5392+ return 0;
5393+ }
5394+
5395+ state->start = time(NULL);
5396+
5397+ _libssh2_debug(session, LIBSSH2_DBG_TRANS,
5398+ "May block until packet of type %d becomes available",
5399+ (int) packet_type);
5400+ }
5401+
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) {
5410+ state->start = 0;
5411+ /* an error which is not just because of blocking */
5412+ return ret;
5413+ } else if (ret == packet_type) {
5414+ /* Be lazy, let packet_ask pull it out of the brigade */
5415+ ret =
5416+ libssh2_packet_ask_ex(session, packet_type, data, data_len,
5417+ match_ofs, match_buf, match_len, 0);
5418+ state->start = 0;
5419+ return ret;
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);
5423+
5424+ if ((left <= 0) || (libssh2_waitsocket(session, left) <= 0)) {
5425+ state->start = 0;
5426+ return PACKET_TIMEOUT;
5427+ }
5428+ }
5429+ }
5430+
5431+ /* Only reached if the socket died */
5432+ return -1;
5433+}
5434+
5435+/* }}} */
5436+
5437+/* {{{ libssh2_packet_burn
5438+ * Loops libssh2_packet_read() until any packet is available and promptly
5439+ * discards it
5440+ * Used during KEX exchange to discard badly guessed KEX_INIT packets
5441+ */
5442+int
5443+libssh2_packet_burn(LIBSSH2_SESSION * session,
5444+ libssh2_nonblocking_states * state)
5445+{
5446+ unsigned char *data;
5447+ unsigned long data_len;
5448+ unsigned char all_packets[255];
5449+ int i;
5450+ int ret;
5451+
5452+ if (*state == libssh2_NB_state_idle) {
5453+ for(i = 1; i < 256; i++) {
5454+ all_packets[i - 1] = i;
5455+ }
5456+
5457+ if (libssh2_packet_askv_ex
5458+ (session, all_packets, &data, &data_len, 0, NULL, 0, 0) == 0) {
5459+ i = data[0];
5460+ /* A packet was available in the packet brigade, burn it */
5461+ LIBSSH2_FREE(session, data);
5462+ return i;
5463+ }
5464+
5465+ _libssh2_debug(session, LIBSSH2_DBG_TRANS,
5466+ "Blocking until packet becomes available to burn");
5467+ *state = libssh2_NB_state_created;
5468+ }
5469+
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;
5475+ return ret;
5476+ } else if (ret == 0) {
5477+ /* FIXME: this might busyloop */
5478+ continue;
5479+ }
5480+
5481+ /* Be lazy, let packet_ask pull it out of the brigade */
5482+ if (0 ==
5483+ libssh2_packet_ask_ex(session, ret, &data, &data_len, 0, NULL, 0,
5484+ 0)) {
5485+ /* Smoke 'em if you got 'em */
5486+ LIBSSH2_FREE(session, data);
5487+ *state = libssh2_NB_state_idle;
5488+ return ret;
5489+ }
5490+ }
5491+
5492+ /* Only reached if the socket died */
5493+ return -1;
5494+}
5495+
5496+/* }}} */
5497+
5498+/*
5499+ * {{{ libssh2_packet_requirev
5500+ *
5501+ * Loops libssh2_packet_read() until one of a list of packet types requested is
5502+ * available
5503+ * SSH_DISCONNECT or a SOCKET_DISCONNECTED will cause a bailout
5504+ * packet_types is a null terminated list of packet_type numbers
5505+ */
5506+
5507+int
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)
5515+{
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
5520+ brigade */
5521+ state->start = 0;
5522+ return 0;
5523+ }
5524+
5525+ if (state->start == 0) {
5526+ state->start = time(NULL);
5527+ }
5528+
5529+ while (session->socket_state != LIBSSH2_SOCKET_DISCONNECTED) {
5530+ int ret = libssh2_packet_read(session);
5531+ if ((ret < 0) && (ret != PACKET_EAGAIN)) {
5532+ state->start = 0;
5533+ return ret;
5534+ }
5535+ if (ret <= 0) {
5536+ long left = LIBSSH2_READ_TIMEOUT - (time(NULL) - state->start);
5537+
5538+ if ((left <= 0) || (libssh2_waitsocket(session, left) <= 0)) {
5539+ state->start = 0;
5540+ return PACKET_TIMEOUT;
5541+ } else if (ret == PACKET_EAGAIN) {
5542+ return PACKET_EAGAIN;
5543+ }
5544+ }
5545+
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,
5550+ match_len, 0);
5551+ }
5552+ }
5553+
5554+ /* Only reached if the socket died */
5555+ state->start = 0;
5556+ return -1;
5557+}
5558+
5559+/* }}} */
5560
5561Property changes on: libssh2/src/packet.c
5562___________________________________________________________________
5563Added: svn:mime-type
5564 + text/x-c
5565Added: svn:keywords
5566 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
5567Added: cvs2svn:cvs-rev
5568 + 1.2
5569Added: svn:eol-style
5570 + native
5571
5572Index: libssh2/src/channel.c
5573===================================================================
5574--- libssh2/src/channel.c (.../tags/RELEASE_0_11_0)
5575+++ libssh2/src/channel.c (.../trunk)
5576@@ -0,0 +1,2260 @@
5577+/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
5578+ * Copyright (c) 2008 by Daniel Stenberg
5579+ *
5580+ * All rights reserved.
5581+ *
5582+ * Redistribution and use in source and binary forms,
5583+ * with or without modification, are permitted provided
5584+ * that the following conditions are met:
5585+ *
5586+ * Redistributions of source code must retain the above
5587+ * copyright notice, this list of conditions and the
5588+ * following disclaimer.
5589+ *
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.
5594+ *
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.
5599+ *
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
5613+ * OF SUCH DAMAGE.
5614+ */
5615+
5616+#include "libssh2_priv.h"
5617+#ifdef HAVE_UNISTD_H
5618+#include <unistd.h>
5619+#endif
5620+#include <fcntl.h>
5621+#ifdef HAVE_INTTYPES_H
5622+#include <inttypes.h>
5623+#endif
5624+
5625+
5626+/* {{{ libssh2_channel_nextid
5627+ * Determine the next channel ID we can use at our end
5628+ */
5629+unsigned long
5630+libssh2_channel_nextid(LIBSSH2_SESSION * session)
5631+{
5632+ unsigned long id = session->next_channel;
5633+ LIBSSH2_CHANNEL *channel;
5634+
5635+ channel = session->channels.head;
5636+
5637+ while (channel) {
5638+ if (channel->local.id > id) {
5639+ id = channel->local.id;
5640+ }
5641+ channel = channel->next;
5642+ }
5643+
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
5649+ * told...
5650+ */
5651+ session->next_channel = id + 1;
5652+ _libssh2_debug(session, LIBSSH2_DBG_CONN, "Allocated new channel ID#%lu",
5653+ id);
5654+ return id;
5655+}
5656+
5657+/* }}} */
5658+
5659+/* {{{ libssh2_channel_locate
5660+ * Locate a channel pointer by number
5661+ */
5662+LIBSSH2_CHANNEL *
5663+libssh2_channel_locate(LIBSSH2_SESSION * session, unsigned long channel_id)
5664+{
5665+ LIBSSH2_CHANNEL *channel = session->channels.head;
5666+ while (channel) {
5667+ if (channel->local.id == channel_id) {
5668+ return channel;
5669+ }
5670+ channel = channel->next;
5671+ }
5672+
5673+ return NULL;
5674+}
5675+
5676+/* }}} */
5677+
5678+#define CHANNEL_ADD(session, channel) \
5679+{ \
5680+ if ((session)->channels.tail) { \
5681+ (session)->channels.tail->next = (channel); \
5682+ (channel)->prev = (session)->channels.tail; \
5683+ } else { \
5684+ (session)->channels.head = (channel); \
5685+ (channel)->prev = NULL; \
5686+ } \
5687+ (channel)->next = NULL; \
5688+ (session)->channels.tail = (channel); \
5689+ (channel)->session = (session); \
5690+}
5691+
5692+/* {{{ libssh2_channel_open_ex
5693+ * Establish a generic session channel
5694+ */
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)
5700+{
5701+ static const unsigned char reply_codes[3] = {
5702+ SSH_MSG_CHANNEL_OPEN_CONFIRMATION,
5703+ SSH_MSG_CHANNEL_OPEN_FAILURE,
5704+ 0
5705+ };
5706+ unsigned char *s;
5707+ int rc;
5708+
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);
5717+
5718+ /* Zero the whole thing out */
5719+ memset(&session->open_packet_requirev_state, 0,
5720+ sizeof(session->open_packet_requirev_state));
5721+
5722+ _libssh2_debug(session, LIBSSH2_DBG_CONN,
5723+ "Opening Channel - win %d pack %d", window_size,
5724+ packet_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);
5730+ return NULL;
5731+ }
5732+ memset(session->open_channel, 0, sizeof(LIBSSH2_CHANNEL));
5733+
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;
5742+ return NULL;
5743+ }
5744+ memcpy(session->open_channel->channel_type, channel_type,
5745+ channel_type_len);
5746+
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;
5752+
5753+ CHANNEL_ADD(session, session->open_channel);
5754+
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;
5761+ }
5762+ *(s++) = SSH_MSG_CHANNEL_OPEN;
5763+ libssh2_htonu32(s, channel_type_len);
5764+ s += 4;
5765+
5766+ memcpy(s, channel_type, channel_type_len);
5767+ s += channel_type_len;
5768+
5769+ libssh2_htonu32(s, session->open_local_channel);
5770+ s += 4;
5771+
5772+ libssh2_htonu32(s, window_size);
5773+ s += 4;
5774+
5775+ libssh2_htonu32(s, packet_size);
5776+ s += 4;
5777+
5778+ if (message && message_len) {
5779+ memcpy(s, message, message_len);
5780+ s += message_len;
5781+ }
5782+
5783+ session->open_state = libssh2_NB_state_created;
5784+ }
5785+
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);
5792+ return NULL;
5793+ } else if (rc) {
5794+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
5795+ "Unable to send channel-open request", 0);
5796+ goto channel_error;
5797+ }
5798+
5799+ session->open_state = libssh2_NB_state_sent;
5800+ }
5801+
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);
5811+ return NULL;
5812+ } else if (rc) {
5813+ goto channel_error;
5814+ }
5815+
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"
5827+ " pack: %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;
5838+
5839+ session->open_state = libssh2_NB_state_idle;
5840+ return session->open_channel;
5841+ }
5842+
5843+ if (session->open_data[0] == SSH_MSG_CHANNEL_OPEN_FAILURE) {
5844+ libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE,
5845+ "Channel open failure", 0);
5846+ }
5847+ }
5848+
5849+ channel_error:
5850+
5851+ if (session->open_data) {
5852+ LIBSSH2_FREE(session, session->open_data);
5853+ session->open_data = NULL;
5854+ }
5855+ if (session->open_packet) {
5856+ LIBSSH2_FREE(session, session->open_packet);
5857+ session->open_packet = NULL;
5858+ }
5859+ if (session->open_channel) {
5860+ unsigned char channel_id[4];
5861+ LIBSSH2_FREE(session, session->open_channel->channel_type);
5862+
5863+ if (session->open_channel->next) {
5864+ session->open_channel->next->prev = session->open_channel->prev;
5865+ }
5866+ if (session->open_channel->prev) {
5867+ session->open_channel->prev->next = session->open_channel->next;
5868+ }
5869+ if (session->channels.head == session->open_channel) {
5870+ session->channels.head = session->open_channel->next;
5871+ }
5872+ if (session->channels.tail == session->open_channel) {
5873+ session->channels.tail = session->open_channel->prev;
5874+ }
5875+
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)
5881+ ||
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;
5887+ }
5888+
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;
5893+ }
5894+
5895+ LIBSSH2_FREE(session, session->open_channel);
5896+ session->open_channel = NULL;
5897+ }
5898+
5899+ session->open_state = libssh2_NB_state_idle;
5900+ return NULL;
5901+}
5902+
5903+/* }}} */
5904+
5905+/* {{{ libssh2_channel_direct_tcpip_ex
5906+ * Tunnel TCP/IP connect through the SSH session to direct host/port
5907+ */
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)
5911+{
5912+ LIBSSH2_CHANNEL *channel;
5913+ unsigned char *s;
5914+
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;
5921+
5922+ _libssh2_debug(session, LIBSSH2_DBG_CONN,
5923+ "Requesting direct-tcpip session to from %s:%d to %s:%d",
5924+ shost, sport, host, port);
5925+
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",
5931+ 0);
5932+ return NULL;
5933+ }
5934+ libssh2_htonu32(s, session->direct_host_len);
5935+ s += 4;
5936+ memcpy(s, host, session->direct_host_len);
5937+ s += session->direct_host_len;
5938+ libssh2_htonu32(s, port);
5939+ s += 4;
5940+
5941+ libssh2_htonu32(s, session->direct_shost_len);
5942+ s += 4;
5943+ memcpy(s, shost, session->direct_shost_len);
5944+ s += session->direct_shost_len;
5945+ libssh2_htonu32(s, sport);
5946+ s += 4;
5947+
5948+ session->direct_state = libssh2_NB_state_created;
5949+ }
5950+
5951+ channel =
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);
5958+ if (!channel) {
5959+ if (libssh2_session_last_errno(session) == LIBSSH2_ERROR_EAGAIN) {
5960+ /* The error code is still set to LIBSSH2_ERROR_EAGAIN */
5961+ return NULL;
5962+ } else {
5963+ LIBSSH2_FREE(session, session->direct_message);
5964+ session->direct_message = NULL;
5965+ return NULL;
5966+ }
5967+ }
5968+
5969+ LIBSSH2_FREE(session, session->direct_message);
5970+ session->direct_message = NULL;
5971+
5972+ return channel;
5973+}
5974+
5975+/* }}} */
5976+
5977+/* {{{ libssh2_channel_forward_listen_ex
5978+ * Bind a port on the remote host and listen for connections
5979+ */
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)
5983+{
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;
5988+ int rc;
5989+
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)
5994+ + port(4) */
5995+ session->fwdLstn_packet_len =
5996+ session->fwdLstn_host_len + (sizeof("tcpip-forward") - 1) + 14;
5997+
5998+ /* Zero the whole thing out */
5999+ memset(&session->fwdLstn_packet_requirev_state, 0,
6000+ sizeof(session->fwdLstn_packet_requirev_state));
6001+
6002+ _libssh2_debug(session, LIBSSH2_DBG_CONN,
6003+ "Requesting tcpip-forward session for %s:%d", host,
6004+ port);
6005+
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);
6011+ return NULL;
6012+ }
6013+
6014+ *(s++) = SSH_MSG_GLOBAL_REQUEST;
6015+ libssh2_htonu32(s, sizeof("tcpip-forward") - 1);
6016+ s += 4;
6017+ memcpy(s, "tcpip-forward", sizeof("tcpip-forward") - 1);
6018+ s += sizeof("tcpip-forward") - 1;
6019+ *(s++) = 0x01; /* want_reply */
6020+
6021+ libssh2_htonu32(s, session->fwdLstn_host_len);
6022+ s += 4;
6023+ memcpy(s, host ? host : "0.0.0.0", session->fwdLstn_host_len);
6024+ s += session->fwdLstn_host_len;
6025+ libssh2_htonu32(s, port);
6026+ s += 4;
6027+
6028+ session->fwdLstn_state = libssh2_NB_state_created;
6029+ }
6030+
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",
6038+ 0);
6039+ return NULL;
6040+ } else if (rc) {
6041+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
6042+ "Unable to send global-request packet for forward "
6043+ "listen request",
6044+ 0);
6045+ LIBSSH2_FREE(session, session->fwdLstn_packet);
6046+ session->fwdLstn_packet = NULL;
6047+ session->fwdLstn_state = libssh2_NB_state_idle;
6048+ return NULL;
6049+ }
6050+ LIBSSH2_FREE(session, session->fwdLstn_packet);
6051+ session->fwdLstn_packet = NULL;
6052+
6053+ session->fwdLstn_state = libssh2_NB_state_sent;
6054+ }
6055+
6056+ if (session->fwdLstn_state == libssh2_NB_state_sent) {
6057+ rc = libssh2_packet_requirev_ex(session, reply_codes, &data, &data_len,
6058+ 0, NULL, 0,
6059+ &session->
6060+ fwdLstn_packet_requirev_state);
6061+ if (rc == PACKET_EAGAIN) {
6062+ libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block", 0);
6063+ return NULL;
6064+ } else if (rc) {
6065+ libssh2_error(session, LIBSSH2_ERROR_PROTO, "Unknown", 0);
6066+ session->fwdLstn_state = libssh2_NB_state_idle;
6067+ return NULL;
6068+ }
6069+
6070+ if (data[0] == SSH_MSG_REQUEST_SUCCESS) {
6071+ LIBSSH2_LISTENER *listener;
6072+
6073+ listener = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_LISTENER));
6074+ if (!listener) {
6075+ libssh2_error(session, LIBSSH2_ERROR_ALLOC,
6076+ "Unable to allocate memory for listener queue",
6077+ 0);
6078+ LIBSSH2_FREE(session, data);
6079+ session->fwdLstn_state = libssh2_NB_state_idle;
6080+ return NULL;
6081+ }
6082+ memset(listener, 0, sizeof(LIBSSH2_LISTENER));
6083+ listener->session = session;
6084+ listener->host =
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",
6089+ 0);
6090+ LIBSSH2_FREE(session, listener);
6091+ LIBSSH2_FREE(session, data);
6092+ session->fwdLstn_state = libssh2_NB_state_idle;
6093+ return NULL;
6094+ }
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",
6102+ listener->port);
6103+ } else {
6104+ listener->port = port;
6105+ }
6106+
6107+ listener->queue_size = 0;
6108+ listener->queue_maxsize = queue_maxsize;
6109+
6110+ listener->next = session->listeners;
6111+ listener->prev = NULL;
6112+ if (session->listeners) {
6113+ session->listeners->prev = listener;
6114+ }
6115+ session->listeners = listener;
6116+
6117+ if (bound_port) {
6118+ *bound_port = listener->port;
6119+ }
6120+
6121+ LIBSSH2_FREE(session, data);
6122+ session->fwdLstn_state = libssh2_NB_state_idle;
6123+ return listener;
6124+ }
6125+
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;
6131+ return NULL;
6132+ }
6133+ }
6134+
6135+ session->fwdLstn_state = libssh2_NB_state_idle;
6136+
6137+ return NULL;
6138+}
6139+
6140+/* }}} */
6141+
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
6145+ *
6146+ * Return 0 on success, PACKET_EAGAIN if would block, -1 on error
6147+ */
6148+LIBSSH2_API int
6149+libssh2_channel_forward_cancel(LIBSSH2_LISTENER * listener)
6150+{
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) +
6156+ port(4) */
6157+ unsigned long packet_len =
6158+ host_len + 14 + sizeof("cancel-tcpip-forward") - 1;
6159+ int rc;
6160+
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);
6165+
6166+ s = packet = LIBSSH2_ALLOC(session, packet_len);
6167+ if (!packet) {
6168+ libssh2_error(session, LIBSSH2_ERROR_ALLOC,
6169+ "Unable to allocate memeory for setenv packet", 0);
6170+ return -1;
6171+ }
6172+
6173+ *(s++) = SSH_MSG_GLOBAL_REQUEST;
6174+ libssh2_htonu32(s, sizeof("cancel-tcpip-forward") - 1);
6175+ s += 4;
6176+ memcpy(s, "cancel-tcpip-forward", sizeof("cancel-tcpip-forward") - 1);
6177+ s += sizeof("cancel-tcpip-forward") - 1;
6178+ *(s++) = 0x00; /* want_reply */
6179+
6180+ libssh2_htonu32(s, host_len);
6181+ s += 4;
6182+ memcpy(s, listener->host, host_len);
6183+ s += host_len;
6184+ libssh2_htonu32(s, listener->port);
6185+ s += 4;
6186+
6187+ listener->chanFwdCncl_state = libssh2_NB_state_created;
6188+ } else {
6189+ packet = listener->chanFwdCncl_data;
6190+ }
6191+
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;
6196+ } else if (rc) {
6197+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
6198+ "Unable to send global-request packet for forward "
6199+ "listen request",
6200+ 0);
6201+ LIBSSH2_FREE(session, packet);
6202+ listener->chanFwdCncl_state = libssh2_NB_state_idle;
6203+ return -1;
6204+ }
6205+ LIBSSH2_FREE(session, packet);
6206+
6207+ listener->chanFwdCncl_state = libssh2_NB_state_sent;
6208+ }
6209+
6210+ while (queued) {
6211+ LIBSSH2_CHANNEL *next = queued->next;
6212+
6213+ rc = libssh2_channel_free(queued);
6214+ if (rc == PACKET_EAGAIN) {
6215+ return PACKET_EAGAIN;
6216+ }
6217+ queued = next;
6218+ }
6219+ LIBSSH2_FREE(session, listener->host);
6220+
6221+ if (listener->next) {
6222+ listener->next->prev = listener->prev;
6223+ }
6224+ if (listener->prev) {
6225+ listener->prev->next = listener->next;
6226+ } else {
6227+ session->listeners = listener->next;
6228+ }
6229+
6230+ LIBSSH2_FREE(session, listener);
6231+
6232+ listener->chanFwdCncl_state = libssh2_NB_state_idle;
6233+
6234+ return 0;
6235+}
6236+
6237+/* }}} */
6238+
6239+/* {{{ libssh2_channel_forward_accept
6240+ * Accept a connection
6241+ */
6242+LIBSSH2_API LIBSSH2_CHANNEL *
6243+libssh2_channel_forward_accept(LIBSSH2_LISTENER * listener)
6244+{
6245+ libssh2pack_t rc;
6246+
6247+ do {
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);
6252+ return NULL;
6253+ }
6254+ } while (rc > 0);
6255+
6256+ if (listener->queue) {
6257+ LIBSSH2_SESSION *session = listener->session;
6258+ LIBSSH2_CHANNEL *channel;
6259+
6260+ channel = listener->queue;
6261+
6262+ listener->queue = listener->queue->next;
6263+ if (listener->queue) {
6264+ listener->queue->prev = NULL;
6265+ }
6266+
6267+ channel->prev = NULL;
6268+ channel->next = session->channels.head;
6269+ session->channels.head = channel;
6270+
6271+ if (channel->next) {
6272+ channel->next->prev = channel;
6273+ } else {
6274+ session->channels.tail = channel;
6275+ }
6276+ listener->queue_size--;
6277+
6278+ return channel;
6279+ }
6280+
6281+ return NULL;
6282+}
6283+
6284+/* }}} */
6285+
6286+/* {{{ libssh2_channel_setenv_ex
6287+ * Set an environment variable prior to requesting a shell/program/subsystem
6288+ */
6289+LIBSSH2_API int
6290+libssh2_channel_setenv_ex(LIBSSH2_CHANNEL * channel, const char *varname,
6291+ unsigned int varname_len, const char *value,
6292+ unsigned int value_len)
6293+{
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;
6299+ int rc;
6300+
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;
6305+
6306+ /* Zero the whole thing out */
6307+ memset(&channel->setenv_packet_requirev_state, 0,
6308+ sizeof(channel->setenv_packet_requirev_state));
6309+
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);
6314+
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);
6320+ return -1;
6321+ }
6322+
6323+ *(s++) = SSH_MSG_CHANNEL_REQUEST;
6324+ libssh2_htonu32(s, channel->remote.id);
6325+ s += 4;
6326+ libssh2_htonu32(s, sizeof("env") - 1);
6327+ s += 4;
6328+ memcpy(s, "env", sizeof("env") - 1);
6329+ s += sizeof("env") - 1;
6330+
6331+ *(s++) = 0x01;
6332+
6333+ libssh2_htonu32(s, varname_len);
6334+ s += 4;
6335+ memcpy(s, varname, varname_len);
6336+ s += varname_len;
6337+
6338+ libssh2_htonu32(s, value_len);
6339+ s += 4;
6340+ memcpy(s, value, value_len);
6341+ s += value_len;
6342+
6343+ channel->setenv_state = libssh2_NB_state_created;
6344+ }
6345+
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;
6351+ } else if (rc) {
6352+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
6353+ "Unable to send channel-request packet for "
6354+ "setenv request",
6355+ 0);
6356+ LIBSSH2_FREE(session, channel->setenv_packet);
6357+ channel->setenv_packet = NULL;
6358+ channel->setenv_state = libssh2_NB_state_idle;
6359+ return -1;
6360+ }
6361+ LIBSSH2_FREE(session, channel->setenv_packet);
6362+ channel->setenv_packet = NULL;
6363+
6364+ libssh2_htonu32(channel->setenv_local_channel, channel->local.id);
6365+
6366+ channel->setenv_state = libssh2_NB_state_sent;
6367+ }
6368+
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,
6372+ &channel->
6373+ setenv_packet_requirev_state);
6374+ if (rc == PACKET_EAGAIN) {
6375+ return PACKET_EAGAIN;
6376+ }
6377+ if (rc) {
6378+ channel->setenv_state = libssh2_NB_state_idle;
6379+ return -1;
6380+ }
6381+
6382+ if (data[0] == SSH_MSG_CHANNEL_SUCCESS) {
6383+ LIBSSH2_FREE(session, data);
6384+ channel->setenv_state = libssh2_NB_state_idle;
6385+ return 0;
6386+ }
6387+
6388+ LIBSSH2_FREE(session, data);
6389+ }
6390+
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;
6394+ return -1;
6395+}
6396+
6397+/* }}} */
6398+
6399+/* {{{ libssh2_channel_request_pty_ex
6400+ * Duh... Request a PTY
6401+ */
6402+LIBSSH2_API int
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)
6407+{
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;
6413+ int rc;
6414+
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;
6420+
6421+ /* Zero the whole thing out */
6422+ memset(&channel->reqPTY_packet_requirev_state, 0,
6423+ sizeof(channel->reqPTY_packet_requirev_state));
6424+
6425+ _libssh2_debug(session, LIBSSH2_DBG_CONN,
6426+ "Allocating tty on channel %lu/%lu", channel->local.id,
6427+ channel->remote.id);
6428+
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);
6434+ return -1;
6435+ }
6436+
6437+ *(s++) = SSH_MSG_CHANNEL_REQUEST;
6438+ libssh2_htonu32(s, channel->remote.id);
6439+ s += 4;
6440+ libssh2_htonu32(s, sizeof("pty-req") - 1);
6441+ s += 4;
6442+ memcpy(s, "pty-req", sizeof("pty-req") - 1);
6443+ s += sizeof("pty-req") - 1;
6444+
6445+ *(s++) = 0x01;
6446+
6447+ libssh2_htonu32(s, term_len);
6448+ s += 4;
6449+ if (term) {
6450+ memcpy(s, term, term_len);
6451+ s += term_len;
6452+ }
6453+
6454+ libssh2_htonu32(s, width);
6455+ s += 4;
6456+ libssh2_htonu32(s, height);
6457+ s += 4;
6458+ libssh2_htonu32(s, width_px);
6459+ s += 4;
6460+ libssh2_htonu32(s, height_px);
6461+ s += 4;
6462+
6463+ libssh2_htonu32(s, modes_len);
6464+ s += 4;
6465+ if (modes) {
6466+ memcpy(s, modes, modes_len);
6467+ s += modes_len;
6468+ }
6469+
6470+ channel->reqPTY_state = libssh2_NB_state_created;
6471+ }
6472+
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;
6478+ } else if (rc) {
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;
6484+ return -1;
6485+ }
6486+ LIBSSH2_FREE(session, channel->reqPTY_packet);
6487+ channel->reqPTY_packet = NULL;
6488+
6489+ libssh2_htonu32(channel->reqPTY_local_channel, channel->local.id);
6490+
6491+ channel->reqPTY_state = libssh2_NB_state_sent;
6492+ }
6493+
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,
6497+ &channel->
6498+ reqPTY_packet_requirev_state);
6499+ if (rc == PACKET_EAGAIN) {
6500+ return PACKET_EAGAIN;
6501+ } else if (rc) {
6502+ channel->reqPTY_state = libssh2_NB_state_idle;
6503+ return -1;
6504+ }
6505+
6506+ if (data[0] == SSH_MSG_CHANNEL_SUCCESS) {
6507+ LIBSSH2_FREE(session, data);
6508+ channel->reqPTY_state = libssh2_NB_state_idle;
6509+ return 0;
6510+ }
6511+ }
6512+
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;
6517+ return -1;
6518+}
6519+
6520+/* }}} */
6521+
6522+LIBSSH2_API int
6523+libssh2_channel_request_pty_size_ex(LIBSSH2_CHANNEL * channel, int width,
6524+ int height, int width_px, int height_px)
6525+{
6526+ LIBSSH2_SESSION *session = channel->session;
6527+ unsigned char *s;
6528+ int rc;
6529+
6530+ if (channel->reqPTY_state == libssh2_NB_state_idle) {
6531+ channel->reqPTY_packet_len = 39;
6532+
6533+ /* Zero the whole thing out */
6534+ memset(&channel->reqPTY_packet_requirev_state, 0,
6535+ sizeof(channel->reqPTY_packet_requirev_state));
6536+
6537+ _libssh2_debug(session, LIBSSH2_DBG_CONN,
6538+ "changing tty size on channel %lu/%lu",
6539+ channel->local.id,
6540+ channel->remote.id);
6541+
6542+ s = channel->reqPTY_packet =
6543+ LIBSSH2_ALLOC(session, channel->reqPTY_packet_len);
6544+
6545+ if (!channel->reqPTY_packet) {
6546+ libssh2_error(session, LIBSSH2_ERROR_ALLOC,
6547+ "Unable to allocate memory for pty-request", 0);
6548+ return -1;
6549+ }
6550+
6551+ *(s++) = SSH_MSG_CHANNEL_REQUEST;
6552+ libssh2_htonu32(s, channel->remote.id);
6553+ s += 4;
6554+ libssh2_htonu32(s, sizeof("window-change") - 1);
6555+ s += 4;
6556+ memcpy(s, "window-change", sizeof("window-change") - 1);
6557+ s += sizeof("window-change") - 1;
6558+
6559+ *(s++) = 0x00; /* Don't reply */
6560+ libssh2_htonu32(s, width);
6561+ s += 4;
6562+ libssh2_htonu32(s, height);
6563+ s += 4;
6564+ libssh2_htonu32(s, width_px);
6565+ s += 4;
6566+ libssh2_htonu32(s, height_px);
6567+ s += 4;
6568+
6569+ channel->reqPTY_state = libssh2_NB_state_created;
6570+ }
6571+
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;
6577+ } else if (rc) {
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;
6583+ return -1;
6584+ }
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;
6589+
6590+ return 0;
6591+ }
6592+
6593+ channel->reqPTY_state = libssh2_NB_state_idle;
6594+ return -1;
6595+}
6596+
6597+/* Keep this an even number */
6598+#define LIBSSH2_X11_RANDOM_COOKIE_LEN 32
6599+
6600+/* {{{ libssh2_channel_x11_req_ex
6601+ * Request X11 forwarding
6602+ */
6603+LIBSSH2_API int
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)
6607+{
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;
6617+ int rc;
6618+
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;
6624+
6625+ /* Zero the whole thing out */
6626+ memset(&channel->reqX11_packet_requirev_state, 0,
6627+ sizeof(channel->reqX11_packet_requirev_state));
6628+
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);
6636+
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);
6642+ return -1;
6643+ }
6644+
6645+ *(s++) = SSH_MSG_CHANNEL_REQUEST;
6646+ libssh2_htonu32(s, channel->remote.id);
6647+ s += 4;
6648+ libssh2_htonu32(s, sizeof("x11-req") - 1);
6649+ s += 4;
6650+ memcpy(s, "x11-req", sizeof("x11-req") - 1);
6651+ s += sizeof("x11-req") - 1;
6652+
6653+ *(s++) = 0x01; /* want_reply */
6654+ *(s++) = single_connection ? 0x01 : 0x00;
6655+
6656+ libssh2_htonu32(s, proto_len);
6657+ s += 4;
6658+ memcpy(s, auth_proto ? auth_proto : "MIT-MAGIC-COOKIE-1", proto_len);
6659+ s += proto_len;
6660+
6661+ libssh2_htonu32(s, cookie_len);
6662+ s += 4;
6663+ if (auth_cookie) {
6664+ memcpy(s, auth_cookie, cookie_len);
6665+ } else {
6666+ int i;
6667+ unsigned char buffer[LIBSSH2_X11_RANDOM_COOKIE_LEN / 2];
6668+
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]);
6672+ }
6673+ }
6674+ s += cookie_len;
6675+
6676+ libssh2_htonu32(s, screen_number);
6677+ s += 4;
6678+
6679+ channel->reqX11_state = libssh2_NB_state_created;
6680+ }
6681+
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;
6687+ }
6688+ if (rc) {
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;
6694+ return -1;
6695+ }
6696+ LIBSSH2_FREE(session, channel->reqX11_packet);
6697+ channel->reqX11_packet = NULL;
6698+
6699+ libssh2_htonu32(channel->reqX11_local_channel, channel->local.id);
6700+
6701+ channel->reqX11_state = libssh2_NB_state_sent;
6702+ }
6703+
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,
6707+ &channel->
6708+ reqX11_packet_requirev_state);
6709+ if (rc == PACKET_EAGAIN) {
6710+ return PACKET_EAGAIN;
6711+ } else if (rc) {
6712+ channel->reqX11_state = libssh2_NB_state_idle;
6713+ return -1;
6714+ }
6715+
6716+ if (data[0] == SSH_MSG_CHANNEL_SUCCESS) {
6717+ LIBSSH2_FREE(session, data);
6718+ channel->reqX11_state = libssh2_NB_state_idle;
6719+ return 0;
6720+ }
6721+ }
6722+
6723+ LIBSSH2_FREE(session, data);
6724+ libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED,
6725+ "Unable to complete request for channel x11-req", 0);
6726+ return -1;
6727+}
6728+
6729+/* }}} */
6730+
6731+/* {{{ libssh2_channel_process_startup
6732+ * Primitive for libssh2_channel_(shell|exec|subsystem)
6733+ */
6734+LIBSSH2_API int
6735+libssh2_channel_process_startup(LIBSSH2_CHANNEL * channel, const char *request,
6736+ unsigned int request_len, const char *message,
6737+ unsigned int message_len)
6738+{
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;
6744+ libssh2pack_t rc;
6745+
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;
6749+
6750+ /* Zero the whole thing out */
6751+ memset(&channel->process_packet_requirev_state, 0,
6752+ sizeof(channel->process_packet_requirev_state));
6753+
6754+ if (message) {
6755+ channel->process_packet_len += message_len + 4;
6756+ }
6757+
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,
6761+ message);
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",
6767+ 0);
6768+ return -1;
6769+ }
6770+
6771+ *(s++) = SSH_MSG_CHANNEL_REQUEST;
6772+ libssh2_htonu32(s, channel->remote.id);
6773+ s += 4;
6774+ libssh2_htonu32(s, request_len);
6775+ s += 4;
6776+ memcpy(s, request, request_len);
6777+ s += request_len;
6778+
6779+ *(s++) = 0x01;
6780+
6781+ if (message) {
6782+ libssh2_htonu32(s, message_len);
6783+ s += 4;
6784+ memcpy(s, message, message_len);
6785+ s += message_len;
6786+ }
6787+
6788+ channel->process_state = libssh2_NB_state_created;
6789+ }
6790+
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;
6796+ } else if (rc) {
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;
6802+ return -1;
6803+ }
6804+ LIBSSH2_FREE(session, channel->process_packet);
6805+ channel->process_packet = NULL;
6806+
6807+ libssh2_htonu32(channel->process_local_channel, channel->local.id);
6808+
6809+ channel->process_state = libssh2_NB_state_sent;
6810+ }
6811+
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,
6815+ &channel->
6816+ process_packet_requirev_state);
6817+ if (rc == PACKET_EAGAIN) {
6818+ return PACKET_EAGAIN;
6819+ } else if (rc) {
6820+ channel->process_state = libssh2_NB_state_idle;
6821+ return -1;
6822+ }
6823+
6824+ if (data[0] == SSH_MSG_CHANNEL_SUCCESS) {
6825+ LIBSSH2_FREE(session, data);
6826+ channel->process_state = libssh2_NB_state_idle;
6827+ return 0;
6828+ }
6829+ }
6830+
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;
6835+ return -1;
6836+}
6837+
6838+/* }}} */
6839+
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
6843+ */
6844+LIBSSH2_API void
6845+libssh2_channel_set_blocking(LIBSSH2_CHANNEL * channel, int blocking)
6846+{
6847+ (void) _libssh2_session_set_blocking(channel->session, blocking);
6848+}
6849+
6850+/* }}} */
6851+
6852+/* {{{ libssh2_channel_flush_ex
6853+ * Flush data from one (or all) stream
6854+ * Returns number of bytes flushed, or -1 on failure
6855+ */
6856+LIBSSH2_API int
6857+libssh2_channel_flush_ex(LIBSSH2_CHANNEL * channel, int streamid)
6858+{
6859+ LIBSSH2_PACKET *packet = channel->session->packets.head;
6860+
6861+ if (channel->flush_state == libssh2_NB_state_idle) {
6862+ channel->flush_refund_bytes = 0;
6863+ channel->flush_flush_bytes = 0;
6864+
6865+ while (packet) {
6866+ LIBSSH2_PACKET *next = packet->next;
6867+ unsigned char packet_type = packet->data[0];
6868+
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 =
6874+ (packet_type ==
6875+ SSH_MSG_CHANNEL_DATA) ? 0 : libssh2_ntohu32(packet->data +
6876+ 5);
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;
6884+
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);
6890+
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;
6894+
6895+ LIBSSH2_FREE(channel->session, packet->data);
6896+ if (packet->prev) {
6897+ packet->prev->next = packet->next;
6898+ } else {
6899+ channel->session->packets.head = packet->next;
6900+ }
6901+ if (packet->next) {
6902+ packet->next->prev = packet->prev;
6903+ } else {
6904+ channel->session->packets.tail = packet->prev;
6905+ }
6906+ LIBSSH2_FREE(channel->session, packet);
6907+ }
6908+ }
6909+ packet = next;
6910+ }
6911+
6912+ channel->flush_state = libssh2_NB_state_created;
6913+ }
6914+
6915+ if (channel->flush_refund_bytes) {
6916+ int rc;
6917+
6918+ rc = libssh2_channel_receive_window_adjust(channel,
6919+ channel->flush_refund_bytes,
6920+ 0);
6921+ if (rc == PACKET_EAGAIN) {
6922+ return PACKET_EAGAIN;
6923+ }
6924+ }
6925+
6926+ channel->flush_state = libssh2_NB_state_idle;
6927+
6928+ return channel->flush_flush_bytes;
6929+}
6930+
6931+/* }}} */
6932+
6933+/* {{{ libssh2_channel_get_exit_status
6934+ * Return the channel's program exit status
6935+ */
6936+LIBSSH2_API int
6937+libssh2_channel_get_exit_status(LIBSSH2_CHANNEL * channel)
6938+{
6939+ return channel->exit_status;
6940+}
6941+
6942+/* }}} */
6943+
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
6948+ *
6949+ * Returns the new size of the receive window (as understood by remote end)
6950+ */
6951+LIBSSH2_API unsigned long
6952+libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL * channel,
6953+ unsigned long adjustment,
6954+ unsigned char force)
6955+{
6956+ int rc;
6957+
6958+ if (channel->adjust_state == libssh2_NB_state_idle) {
6959+ if (!force
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;
6968+ }
6969+
6970+ if (!adjustment && !channel->adjust_queue) {
6971+ return channel->remote.window_size;
6972+ }
6973+
6974+ adjustment += channel->adjust_queue;
6975+ channel->adjust_queue = 0;
6976+
6977+
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);
6986+
6987+ channel->adjust_state = libssh2_NB_state_created;
6988+ }
6989+
6990+ rc = libssh2_packet_write(channel->session, channel->adjust_adjust, 9);
6991+ if (rc == PACKET_EAGAIN) {
6992+ return PACKET_EAGAIN;
6993+ } else if (rc) {
6994+ libssh2_error(channel->session, LIBSSH2_ERROR_SOCKET_SEND,
6995+ "Unable to send transfer-window adjustment packet, "
6996+ "deferring",
6997+ 0);
6998+ channel->adjust_queue = adjustment;
6999+ channel->adjust_state = libssh2_NB_state_idle;
7000+ } else {
7001+ channel->adjust_state = libssh2_NB_state_idle;
7002+ channel->remote.window_size += adjustment;
7003+ }
7004+
7005+ return channel->remote.window_size;
7006+}
7007+
7008+/* }}} */
7009+
7010+/* {{{ libssh2_channel_handle_extended_data
7011+ *
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)
7016+ */
7017+LIBSSH2_API void
7018+libssh2_channel_handle_extended_data(LIBSSH2_CHANNEL * channel,
7019+ int ignore_mode)
7020+{
7021+ while (libssh2_channel_handle_extended_data2(channel, ignore_mode) ==
7022+ PACKET_EAGAIN);
7023+}
7024+
7025+LIBSSH2_API int
7026+libssh2_channel_handle_extended_data2(LIBSSH2_CHANNEL * channel,
7027+ int ignore_mode)
7028+{
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;
7034+
7035+ channel->extData2_state = libssh2_NB_state_created;
7036+ }
7037+
7038+ if (channel->extData2_state == libssh2_NB_state_idle) {
7039+ if (ignore_mode == LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE) {
7040+ if (libssh2_channel_flush_ex
7041+ (channel,
7042+ LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA) == PACKET_EAGAIN) {
7043+ return PACKET_EAGAIN;
7044+ }
7045+ }
7046+ }
7047+
7048+ channel->extData2_state = libssh2_NB_state_idle;
7049+ return 0;
7050+}
7051+
7052+/* }}} */
7053+
7054+/*
7055+ * {{{ libssh2_channel_read_ex
7056+ * Read data from a channel blocking or non-blocking depending on set state
7057+ *
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
7061+ * PACKET_EAGAIN.
7062+ */
7063+LIBSSH2_API ssize_t
7064+libssh2_channel_read_ex(LIBSSH2_CHANNEL * channel, int stream_id, char *buf,
7065+ size_t buflen)
7066+{
7067+ LIBSSH2_SESSION *session = channel->session;
7068+ libssh2pack_t rc = 0;
7069+
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,
7074+ stream_id);
7075+
7076+ /* process all incoming packets */
7077+ do {
7078+ if (libssh2_waitsocket(session, 0) > 0) {
7079+ rc = libssh2_packet_read(session);
7080+ } else {
7081+ /* Set for PACKET_EAGAIN so we continue */
7082+ rc = PACKET_EAGAIN;
7083+ }
7084+ } while (rc > 0);
7085+
7086+ if ((rc < 0) && (rc != PACKET_EAGAIN)) {
7087+ return rc;
7088+ }
7089+ channel->read_bytes_read = 0;
7090+
7091+ channel->read_packet = session->packets.head;
7092+ channel->read_state = libssh2_NB_state_created;
7093+ }
7094+
7095+ /*
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
7099+ */
7100+ if (channel->read_state == libssh2_NB_state_jump1) {
7101+ goto channel_read_ex_point1;
7102+ }
7103+
7104+ rc = 0;
7105+ channel->read_block = 0;
7106+
7107+ do {
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
7111+ * data. */
7112+ if ( channel->read_bytes_read < (int) buflen) {
7113+ rc = libssh2_packet_read(session);
7114+
7115+ /* If we didn't find any more data to read */
7116+ if (rc < 0) {
7117+ if ( channel->read_bytes_read > 0){
7118+ break; /* finish processing and return */
7119+ }
7120+
7121+ /* no packets available, no data read. */
7122+ channel->read_state = libssh2_NB_state_idle;
7123+ return rc;
7124+ }
7125+ /* We read more data, restart our processing at the beginning
7126+ * of our packet list. */
7127+ channel->read_packet = session->packets.head;
7128+ }
7129+ else { /* The read buffer is full, finish processing and return */
7130+ break;
7131+ }
7132+ }
7133+
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;
7138+
7139+ channel->read_local_id =
7140+ libssh2_ntohu32(channel->read_packet->data + 1);
7141+
7142+ /*
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
7148+ */
7149+ if ((stream_id
7150+ && (channel->read_packet->data[0] ==
7151+ SSH_MSG_CHANNEL_EXTENDED_DATA)
7152+ && (channel->local.id == channel->read_local_id)
7153+ && (stream_id ==
7154+ (int) libssh2_ntohu32(channel->read_packet->data + 5)))
7155+ || (!stream_id
7156+ && (channel->read_packet->data[0] == SSH_MSG_CHANNEL_DATA)
7157+ && (channel->local.id == channel->read_local_id))
7158+ || (!stream_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))) {
7164+
7165+ channel->read_want = buflen - channel->read_bytes_read;
7166+ channel->read_unlink_packet = 0;
7167+
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;
7175+ }
7176+
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;
7186+
7187+ if (channel->read_unlink_packet) {
7188+ if (channel->read_packet->prev) {
7189+ channel->read_packet->prev->next =
7190+ channel->read_packet->next;
7191+ } else {
7192+ session->packets.head = channel->read_packet->next;
7193+ }
7194+ if (channel->read_packet->next) {
7195+ channel->read_packet->next->prev =
7196+ channel->read_packet->prev;
7197+ } else {
7198+ session->packets.tail = channel->read_packet->prev;
7199+ }
7200+ LIBSSH2_FREE(session, channel->read_packet->data);
7201+
7202+
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,
7210+ channel->
7211+ read_packet->
7212+ data_len -
7213+ (stream_id ? 13
7214+ : 9), 0);
7215+ if (rc == PACKET_EAGAIN) {
7216+ return PACKET_EAGAIN;
7217+ }
7218+ channel->read_state = libssh2_NB_state_created;
7219+ LIBSSH2_FREE(session, channel->read_packet);
7220+ channel->read_packet = NULL;
7221+ }
7222+ }
7223+ channel->read_packet = channel->read_next;
7224+ }
7225+ channel->read_block = 1;
7226+ } while ((channel->read_bytes_read == 0) && !channel->remote.close);
7227+
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);
7233+ } else {
7234+ /*
7235+ * when non-blocking, we must return PACKET_EAGAIN if we haven't
7236+ * completed reading the channel
7237+ */
7238+ if (!libssh2_channel_eof(channel)) {
7239+ return PACKET_EAGAIN;
7240+ }
7241+ }
7242+ }
7243+
7244+ channel->read_state = libssh2_NB_state_idle;
7245+ return channel->read_bytes_read;
7246+}
7247+
7248+/* }}} */
7249+
7250+/*
7251+ * {{{ libssh2_channel_packet_data_len
7252+ * Return the size of the data block of the current packet, or 0 if there
7253+ * isn't a packet.
7254+ */
7255+unsigned long
7256+libssh2_channel_packet_data_len(LIBSSH2_CHANNEL * channel, int stream_id)
7257+{
7258+ LIBSSH2_SESSION *session = channel->session;
7259+ LIBSSH2_PACKET *read_packet;
7260+ uint32_t read_local_id;
7261+
7262+ if ((read_packet = session->packets.head) == NULL) {
7263+ return 0;
7264+ }
7265+
7266+ while (read_packet) {
7267+ read_local_id = libssh2_ntohu32(read_packet->data + 1);
7268+
7269+ /*
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
7275+ */
7276+ if ((stream_id
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)) ||
7282+ (!stream_id
7283+ && (read_packet->
7284+ data[0] ==
7285+ SSH_MSG_CHANNEL_EXTENDED_DATA)
7286+ && (channel->
7287+ local.id ==
7288+ read_local_id)
7289+ && (channel->
7290+ remote.
7291+ extended_data_ignore_mode
7292+ ==
7293+ LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE)))
7294+ {
7295+ return (read_packet->data_len - read_packet->data_head);
7296+ }
7297+ read_packet = read_packet->next;
7298+ }
7299+
7300+ return 0;
7301+}
7302+
7303+/* }}} */
7304+
7305+/* {{{ libssh2_channel_write_ex
7306+ * Send data to a channel
7307+ */
7308+LIBSSH2_API ssize_t
7309+libssh2_channel_write_ex(LIBSSH2_CHANNEL * channel, int stream_id,
7310+ const char *buf, size_t buflen)
7311+{
7312+ LIBSSH2_SESSION *session = channel->session;
7313+ libssh2pack_t rc;
7314+
7315+ if (channel->write_state == libssh2_NB_state_idle) {
7316+ channel->write_bufwrote = 0;
7317+
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,
7321+ stream_id);
7322+
7323+ if (channel->local.close) {
7324+ libssh2_error(session, LIBSSH2_ERROR_CHANNEL_CLOSED,
7325+ "We've already closed this channel", 0);
7326+ return -1;
7327+ }
7328+
7329+ if (channel->local.eof) {
7330+ libssh2_error(session, LIBSSH2_ERROR_CHANNEL_EOF_SENT,
7331+ "EOF has already been sight, data might be ignored",
7332+ 0);
7333+ }
7334+
7335+ /* [13] 9 = packet_type(1) + channelno(4) [ + streamid(4) ] +
7336+ buflen(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",
7343+ 0);
7344+ return -1;
7345+ }
7346+
7347+ channel->write_state = libssh2_NB_state_allocated;
7348+ }
7349+
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;
7354+
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;
7360+ if (stream_id) {
7361+ libssh2_htonu32(channel->write_s, stream_id);
7362+ channel->write_s += 4;
7363+ }
7364+
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);
7370+
7371+ if (rc < 0) {
7372+ /* Error or EAGAIN occurred, disconnect? */
7373+ if (rc != PACKET_EAGAIN) {
7374+ channel->write_state = libssh2_NB_state_idle;
7375+ }
7376+ return rc;
7377+ }
7378+
7379+ if ((rc == 0) && (session->socket_block == 0)) {
7380+ /*
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
7384+ */
7385+ return PACKET_EAGAIN;
7386+ }
7387+ }
7388+
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;
7398+ }
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;
7406+ }
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;
7411+
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);
7416+
7417+ channel->write_state = libssh2_NB_state_created;
7418+ }
7419+
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;
7428+ }
7429+ else if (rc) {
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;
7435+ return -1;
7436+ }
7437+ /* Shrink local window size */
7438+ channel->local.window_size -= channel->write_bufwrite;
7439+
7440+ /* Adjust buf for next iteration */
7441+ buflen -= channel->write_bufwrite;
7442+ buf += channel->write_bufwrite;
7443+ channel->write_bufwrote += channel->write_bufwrite;
7444+
7445+ channel->write_state = libssh2_NB_state_allocated;
7446+
7447+ /*
7448+ * Not sure this is still wanted
7449+ if (!channel->session->socket_block) {
7450+ break;
7451+ }
7452+ */
7453+ }
7454+ }
7455+
7456+ LIBSSH2_FREE(session, channel->write_packet);
7457+ channel->write_packet = NULL;
7458+
7459+ channel->write_state = libssh2_NB_state_idle;
7460+
7461+ return channel->write_bufwrote;
7462+}
7463+
7464+/* }}} */
7465+
7466+/* {{{ libssh2_channel_send_eof
7467+ * Send EOF on channel
7468+ */
7469+LIBSSH2_API int
7470+libssh2_channel_send_eof(LIBSSH2_CHANNEL * channel)
7471+{
7472+ LIBSSH2_SESSION *session = channel->session;
7473+ unsigned char packet[5]; /* packet_type(1) + channelno(4) */
7474+ int rc;
7475+
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;
7483+ } else if (rc) {
7484+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
7485+ "Unable to send EOF on channel", 0);
7486+ return -1;
7487+ }
7488+ channel->local.eof = 1;
7489+
7490+ return 0;
7491+}
7492+
7493+/* }}} */
7494+
7495+/* {{{ libssh2_channel_eof
7496+ * Read channel's eof status
7497+ */
7498+LIBSSH2_API int
7499+libssh2_channel_eof(LIBSSH2_CHANNEL * channel)
7500+{
7501+ LIBSSH2_SESSION *session = channel->session;
7502+ LIBSSH2_PACKET *packet = session->packets.head;
7503+
7504+ while (packet) {
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 */
7509+ return 0;
7510+ }
7511+ packet = packet->next;
7512+ }
7513+
7514+ return channel->remote.eof;
7515+}
7516+
7517+/* }}} */
7518+
7519+/* {{{ libssh2_channel_wait_eof
7520+* Awaiting channel EOF
7521+*/
7522+LIBSSH2_API int
7523+libssh2_channel_wait_eof(LIBSSH2_CHANNEL * channel)
7524+{
7525+ LIBSSH2_SESSION *session = channel->session;
7526+ int rc;
7527+
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);
7532+
7533+ channel->wait_eof_state = libssh2_NB_state_created;
7534+ }
7535+
7536+ /*
7537+ * While channel is not eof, read more packets from the network.
7538+ * Either the EOF will be set or network timeout will occur.
7539+ */
7540+ do {
7541+ if (channel->remote.eof) {
7542+ break;
7543+ }
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;
7549+ return -1;
7550+ }
7551+ } while (1);
7552+
7553+ channel->wait_eof_state = libssh2_NB_state_idle;
7554+
7555+ return 0;
7556+}
7557+
7558+/* }}} */
7559+
7560+
7561+/* {{{ libssh2_channel_close
7562+ * Close a channel
7563+ */
7564+LIBSSH2_API int
7565+libssh2_channel_close(LIBSSH2_CHANNEL * channel)
7566+{
7567+ LIBSSH2_SESSION *session = channel->session;
7568+ int rc = 0;
7569+ int retcode;
7570+
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;
7575+ return 0;
7576+ }
7577+
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);
7581+
7582+ if (channel->close_cb) {
7583+ LIBSSH2_CHANNEL_CLOSE(session, channel);
7584+ }
7585+ channel->local.close = 1;
7586+
7587+ channel->close_packet[0] = SSH_MSG_CHANNEL_CLOSE;
7588+ libssh2_htonu32(channel->close_packet + 1, channel->remote.id);
7589+
7590+ channel->close_state = libssh2_NB_state_created;
7591+ }
7592+
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;
7601+ return -1;
7602+ }
7603+
7604+ channel->close_state = libssh2_NB_state_sent;
7605+ }
7606+
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;
7611+
7612+ do {
7613+ ret = libssh2_packet_read(session);
7614+ if (ret == PACKET_EAGAIN) {
7615+ return PACKET_EAGAIN;
7616+ } else if (ret < 0) {
7617+ rc = -1;
7618+ }
7619+ } while ((ret != SSH_MSG_CHANNEL_CLOSE) && (rc == 0));
7620+ }
7621+ }
7622+
7623+ channel->close_state = libssh2_NB_state_idle;
7624+
7625+ return rc;
7626+}
7627+
7628+/* }}} */
7629+
7630+/* {{{ libssh2_channel_wait_closed
7631+ * Awaiting channel close after EOF
7632+ */
7633+LIBSSH2_API int
7634+libssh2_channel_wait_closed(LIBSSH2_CHANNEL * channel)
7635+{
7636+ LIBSSH2_SESSION *session = channel->session;
7637+ int rc;
7638+
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",
7643+ 0);
7644+ return -1;
7645+ }
7646+
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);
7651+
7652+ channel->wait_closed_state = libssh2_NB_state_created;
7653+ }
7654+
7655+ /*
7656+ * While channel is not closed, read more packets from the network.
7657+ * Either the channel will be closed or network timeout will occur.
7658+ */
7659+ do {
7660+ if (!channel->remote.close) {
7661+ break;
7662+ }
7663+ rc = libssh2_packet_read(session);
7664+ if (rc == PACKET_EAGAIN) {
7665+ return PACKET_EAGAIN;
7666+ } else if (rc <= 0) {
7667+ break;
7668+ }
7669+ } while (1);
7670+
7671+ channel->wait_closed_state = libssh2_NB_state_idle;
7672+
7673+ return 0;
7674+}
7675+
7676+/* }}} */
7677+
7678+
7679+/* {{{ libssh2_channel_free
7680+ * Make sure a channel is closed, then remove the channel from the session
7681+ * and free its resource(s)
7682+ *
7683+ * Returns 0 on success, -1 on failure
7684+ */
7685+LIBSSH2_API int
7686+libssh2_channel_free(LIBSSH2_CHANNEL * channel)
7687+{
7688+ LIBSSH2_SESSION *session = channel->session;
7689+ unsigned char channel_id[4];
7690+ unsigned char *data;
7691+ unsigned long data_len;
7692+ int rc;
7693+
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);
7698+
7699+ channel->free_state = libssh2_NB_state_created;
7700+ }
7701+
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);
7706+ if (rc) {
7707+ channel->free_state = libssh2_NB_state_idle;
7708+ return -1;
7709+ }
7710+ }
7711+
7712+ channel->free_state = libssh2_NB_state_idle;
7713+
7714+ /*
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
7718+ */
7719+
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,
7724+ 0) >= 0)
7725+ ||
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);
7730+ }
7731+
7732+ /* free "channel_type" */
7733+ if (channel->channel_type) {
7734+ LIBSSH2_FREE(session, channel->channel_type);
7735+ }
7736+
7737+ /* Unlink from channel brigade */
7738+ if (channel->prev) {
7739+ channel->prev->next = channel->next;
7740+ } else {
7741+ session->channels.head = channel->next;
7742+ }
7743+ if (channel->next) {
7744+ channel->next->prev = channel->prev;
7745+ } else {
7746+ session->channels.tail = channel->prev;
7747+ }
7748+
7749+ /*
7750+ * Make sure all memory used in the state variables are free
7751+ */
7752+ if (channel->setenv_packet) {
7753+ LIBSSH2_FREE(session, channel->setenv_packet);
7754+ }
7755+ if (channel->reqPTY_packet) {
7756+ LIBSSH2_FREE(session, channel->reqPTY_packet);
7757+ }
7758+ if (channel->reqX11_packet) {
7759+ LIBSSH2_FREE(session, channel->reqX11_packet);
7760+ }
7761+ if (channel->process_packet) {
7762+ LIBSSH2_FREE(session, channel->process_packet);
7763+ }
7764+ if (channel->write_packet) {
7765+ LIBSSH2_FREE(session, channel->write_packet);
7766+ }
7767+
7768+ LIBSSH2_FREE(session, channel);
7769+
7770+ return 0;
7771+}
7772+
7773+/* }}} */
7774+
7775+/* {{{ libssh2_channel_window_read_ex
7776+ *
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
7782+ */
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)
7787+{
7788+ if (window_size_initial) {
7789+ *window_size_initial = channel->remote.window_size_initial;
7790+ }
7791+
7792+ if (read_avail) {
7793+ unsigned long bytes_queued = 0;
7794+ LIBSSH2_PACKET *packet = channel->session->packets.head;
7795+
7796+ while (packet) {
7797+ unsigned char packet_type = packet->data[0];
7798+
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;
7803+ }
7804+
7805+ packet = packet->next;
7806+ }
7807+
7808+ *read_avail = bytes_queued;
7809+ }
7810+
7811+ return channel->remote.window_size;
7812+}
7813+
7814+/* }}} */
7815+
7816+/* {{{ libssh2_channel_window_write_ex
7817+ *
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
7822+ */
7823+LIBSSH2_API unsigned long
7824+libssh2_channel_window_write_ex(LIBSSH2_CHANNEL * channel,
7825+ unsigned long *window_size_initial)
7826+{
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;
7831+ }
7832+
7833+ return channel->local.window_size;
7834+}
7835+
7836+/* }}} */
7837
7838Property changes on: libssh2/src/channel.c
7839___________________________________________________________________
7840Added: svn:mime-type
7841 + text/x-c
7842Added: svn:keywords
7843 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
7844Added: cvs2svn:cvs-rev
7845 + 1.2
7846Added: svn:eol-style
7847 + native
7848
7849Index: libssh2/src/libssh2_priv.h
7850===================================================================
7851--- libssh2/src/libssh2_priv.h (.../tags/RELEASE_0_11_0)
7852+++ libssh2/src/libssh2_priv.h (.../trunk)
7853@@ -0,0 +1,1211 @@
7854+/* Copyright (c) 2004-2008, Sara Golemon <sarag@libssh2.org>
7855+ * All rights reserved.
7856+ *
7857+ * Redistribution and use in source and binary forms,
7858+ * with or without modification, are permitted provided
7859+ * that the following conditions are met:
7860+ *
7861+ * Redistributions of source code must retain the above
7862+ * copyright notice, this list of conditions and the
7863+ * following disclaimer.
7864+ *
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.
7869+ *
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.
7874+ *
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
7888+ * OF SUCH DAMAGE.
7889+ */
7890+
7891+#ifndef LIBSSH2_PRIV_H
7892+#define LIBSSH2_PRIV_H 1
7893+
7894+#define LIBSSH2_LIBRARY
7895+#include "libssh2_config.h"
7896+
7897+#ifdef HAVE_WINDOWS_H
7898+#include <windows.h>
7899+#endif
7900+
7901+#ifdef HAVE_WS2TCPIP_H
7902+#include <ws2tcpip.h>
7903+#endif
7904+
7905+#include <stdio.h>
7906+#include <time.h>
7907+
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
7917+*/
7918+#ifdef HAVE_POLL
7919+# include <sys/poll.h>
7920+#else
7921+# if defined(HAVE_SELECT) && !defined(WIN32)
7922+# ifdef HAVE_SYS_SELECT_H
7923+# include <sys/select.h>
7924+# else
7925+# include <sys/time.h>
7926+# include <sys/types.h>
7927+# endif
7928+# endif
7929+#endif
7930+
7931+#include "libssh2.h"
7932+#include "libssh2_publickey.h"
7933+#include "libssh2_sftp.h"
7934+
7935+/* Provide iovec / writev on WIN32 platform. */
7936+#ifdef WIN32
7937+
7938+/* same as WSABUF */
7939+struct iovec {
7940+ u_long iov_len;
7941+ char *iov_base;
7942+};
7943+
7944+#define inline __inline
7945+
7946+static inline int writev(int sock, struct iovec *iov, int nvecs)
7947+{
7948+ DWORD ret;
7949+ if (WSASend(sock, (LPWSABUF)iov, nvecs, &ret, 0, NULL, NULL) == 0) {
7950+ return ret;
7951+ }
7952+ return -1;
7953+}
7954+
7955+#endif /* WIN32 */
7956+
7957+/* Needed for struct iovec on some platforms */
7958+#ifdef HAVE_SYS_UIO_H
7959+#include <sys/uio.h>
7960+#endif
7961+
7962+#ifdef HAVE_SYS_SOCKET_H
7963+# include <sys/socket.h>
7964+#endif
7965+#ifdef HAVE_SYS_IOCTL_H
7966+# include <sys/ioctl.h>
7967+#endif
7968+#ifdef HAVE_INTTYPES_H
7969+#include <inttypes.h>
7970+#endif
7971+
7972+#ifdef LIBSSH2_LIBGCRYPT
7973+#include "libgcrypt.h"
7974+#else
7975+#include "openssl.h"
7976+#endif
7977+
7978+#ifdef HAVE_WINSOCK2_H
7979+
7980+#include <winsock2.h>
7981+#include <mswsock.h>
7982+#include <ws2tcpip.h>
7983+
7984+#ifdef _MSC_VER
7985+/* "inline" keyword is valid only with C++ engine! */
7986+#define inline __inline
7987+#endif
7988+
7989+/* not really usleep, but safe for the way we use it in this lib */
7990+static inline int usleep(int udelay)
7991+{
7992+ Sleep(udelay / 1000);
7993+ return 0;
7994+}
7995+
7996+#endif
7997+
7998+/* RFC4253 section 6.1 Maximum Packet Length says:
7999+ *
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.)."
8004+ */
8005+#define MAX_SSH_PACKET_LEN 35000
8006+
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)
8010+
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)
8016+
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))
8019+
8020+#define LIBSSH2_CHANNEL_CLOSE(session, channel) channel->close_cb((session), &(session)->abstract, (channel), &(channel)->abstract)
8021+
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;
8027+
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;
8031+
8032+typedef int libssh2pack_t;
8033+
8034+typedef enum
8035+{
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;
8051+
8052+typedef struct packet_require_state_t
8053+{
8054+ libssh2_nonblocking_states state;
8055+ time_t start;
8056+} packet_require_state_t;
8057+
8058+typedef struct packet_requirev_state_t
8059+{
8060+ time_t start;
8061+} packet_requirev_state_t;
8062+
8063+typedef struct kmdhgGPsha1kex_state_t
8064+{
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];
8070+ unsigned char c;
8071+ unsigned long e_packet_len;
8072+ unsigned long s_packet_len;
8073+ unsigned long tmp_len;
8074+ _libssh2_bn_ctx *ctx;
8075+ _libssh2_bn *x;
8076+ _libssh2_bn *e;
8077+ _libssh2_bn *f;
8078+ _libssh2_bn *k;
8079+ unsigned char *s;
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;
8090+
8091+typedef struct key_exchange_state_low_t
8092+{
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;
8103+
8104+typedef struct key_exchange_state_t
8105+{
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;
8114+
8115+#define FwdNotReq "Forward not requested"
8116+
8117+typedef struct packet_queue_listener_state_t
8118+{
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;
8126+ uint32_t port;
8127+ uint32_t sport;
8128+ uint32_t host_len;
8129+ uint32_t shost_len;
8130+} packet_queue_listener_state_t;
8131+
8132+#define X11FwdUnAvil "X11 Forward Unavailable"
8133+
8134+typedef struct packet_x11_open_state_t
8135+{
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;
8142+ uint32_t sport;
8143+ uint32_t shost_len;
8144+} packet_x11_open_state_t;
8145+
8146+struct _LIBSSH2_PACKET
8147+{
8148+ unsigned char type;
8149+
8150+ /* Unencrypted Payload (no type byte, no padding, just the facts ma'am) */
8151+ unsigned char *data;
8152+ unsigned long data_len;
8153+
8154+ /* Where to start reading data from,
8155+ * used for channel data that's been partially consumed */
8156+ unsigned long data_head;
8157+
8158+ /* Can the message be confirmed? */
8159+ int mac;
8160+
8161+ LIBSSH2_PACKET_BRIGADE *brigade;
8162+
8163+ LIBSSH2_PACKET *next, *prev;
8164+};
8165+
8166+struct _LIBSSH2_PACKET_BRIGADE
8167+{
8168+ LIBSSH2_PACKET *head, *tail;
8169+};
8170+
8171+typedef struct _libssh2_channel_data
8172+{
8173+ /* Identifier */
8174+ unsigned long id;
8175+
8176+ /* Limits and restrictions */
8177+ unsigned long window_size_initial, window_size, packet_size;
8178+
8179+ /* Set to 1 when CHANNEL_CLOSE / CHANNEL_EOF sent/received */
8180+ char close, eof, extended_data_ignore_mode;
8181+} libssh2_channel_data;
8182+
8183+struct _LIBSSH2_CHANNEL
8184+{
8185+ unsigned char *channel_type;
8186+ unsigned channel_type_len;
8187+
8188+ /* channel's program exit status */
8189+ int exit_status;
8190+
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;
8194+
8195+ LIBSSH2_SESSION *session;
8196+
8197+ LIBSSH2_CHANNEL *next, *prev;
8198+
8199+ void *abstract;
8200+ LIBSSH2_CHANNEL_CLOSE_FUNC((*close_cb));
8201+
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;
8208+
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;
8215+
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;
8222+
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;
8229+
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;
8234+
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) */
8238+
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;
8243+ int read_block;
8244+ int read_bytes_read;
8245+ uint32_t read_local_id;
8246+ int read_want;
8247+ int read_unlink_packet;
8248+
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;
8256+
8257+ /* State variables used in libssh2_channel_close() */
8258+ libssh2_nonblocking_states close_state;
8259+ unsigned char close_packet[5];
8260+
8261+ /* State variables used in libssh2_channel_wait_closedeof() */
8262+ libssh2_nonblocking_states wait_eof_state;
8263+
8264+ /* State variables used in libssh2_channel_wait_closed() */
8265+ libssh2_nonblocking_states wait_closed_state;
8266+
8267+ /* State variables used in libssh2_channel_free() */
8268+ libssh2_nonblocking_states free_state;
8269+
8270+ /* State variables used in libssh2_channel_handle_extended_data2() */
8271+ libssh2_nonblocking_states extData2_state;
8272+};
8273+
8274+struct _LIBSSH2_CHANNEL_BRIGADE
8275+{
8276+ LIBSSH2_CHANNEL *head, *tail;
8277+};
8278+
8279+struct _LIBSSH2_LISTENER
8280+{
8281+ LIBSSH2_SESSION *session;
8282+
8283+ char *host;
8284+ int port;
8285+
8286+ LIBSSH2_CHANNEL *queue;
8287+ int queue_size;
8288+ int queue_maxsize;
8289+
8290+ LIBSSH2_LISTENER *prev, *next;
8291+
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;
8296+};
8297+
8298+typedef struct _libssh2_endpoint_data
8299+{
8300+ unsigned char *banner;
8301+
8302+ unsigned char *kexinit;
8303+ unsigned long kexinit_len;
8304+
8305+ const LIBSSH2_CRYPT_METHOD *crypt;
8306+ void *crypt_abstract;
8307+
8308+ const LIBSSH2_MAC_METHOD *mac;
8309+ unsigned long seqno;
8310+ void *mac_abstract;
8311+
8312+ const LIBSSH2_COMP_METHOD *comp;
8313+ void *comp_abstract;
8314+
8315+ /* Method Preferences -- NULL yields "load order" */
8316+ char *crypt_prefs;
8317+ char *mac_prefs;
8318+ char *comp_prefs;
8319+ char *lang_prefs;
8320+} libssh2_endpoint_data;
8321+
8322+#define PACKETBUFSIZE 4096
8323+
8324+struct transportpacket
8325+{
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
8331+ the buffer */
8332+ int readidx; /* at what array index we do the next read from
8333+ the buffer */
8334+ int packet_length; /* the most recent packet_length as read from the
8335+ network data */
8336+ int padding_length; /* the most recent padding_length as read from the
8337+ network data */
8338+ int data_num; /* How much of the total package that has been read
8339+ so far. */
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 +
8343+ mac_length. */
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 */
8348+
8349+ /* ------------- for outgoing data --------------- */
8350+ unsigned char *outbuf; /* pointer to a LIBSSH2_ALLOC() area for the
8351+ outgoing data */
8352+ int ototal_num; /* size of outbuf in number of bytes */
8353+ unsigned char *odata; /* original pointer to the data we stored in
8354+ outbuf */
8355+ unsigned long olen; /* original size of the data we stored in
8356+ outbuf */
8357+ unsigned long osent; /* number of bytes already sent */
8358+};
8359+
8360+struct _LIBSSH2_PUBLICKEY
8361+{
8362+ LIBSSH2_CHANNEL *channel;
8363+ unsigned long version;
8364+
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;
8369+
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;
8374+
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;
8379+
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;
8386+};
8387+
8388+#define SFTP_HANDLE_MAXLEN 256 /* according to spec! */
8389+
8390+struct _LIBSSH2_SFTP_HANDLE
8391+{
8392+ LIBSSH2_SFTP *sftp;
8393+ LIBSSH2_SFTP_HANDLE *prev, *next;
8394+
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];
8399+
8400+ char handle[SFTP_HANDLE_MAXLEN];
8401+ int handle_len;
8402+
8403+ char handle_type;
8404+
8405+ union _libssh2_sftp_handle_data
8406+ {
8407+ struct _libssh2_sftp_handle_file_data
8408+ {
8409+ libssh2_uint64_t offset;
8410+ } file;
8411+ struct _libssh2_sftp_handle_dir_data
8412+ {
8413+ unsigned long names_left;
8414+ void *names_packet;
8415+ char *next_name;
8416+ } dir;
8417+ } u;
8418+
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;
8423+};
8424+
8425+struct _LIBSSH2_SFTP
8426+{
8427+ LIBSSH2_CHANNEL *channel;
8428+
8429+ unsigned long request_id, version;
8430+
8431+ LIBSSH2_PACKET_BRIGADE packets;
8432+
8433+ LIBSSH2_SFTP_HANDLE *handles;
8434+
8435+ unsigned long last_errno;
8436+
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 */
8441+
8442+ /* Time that libssh2_sftp_packet_requirev() started reading */
8443+ time_t requirev_start;
8444+
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;
8450+
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;
8456+
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;
8461+
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;
8466+
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;
8471+
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;
8476+
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;
8482+
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;
8487+
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;
8492+
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;
8497+
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;
8502+};
8503+
8504+#define LIBSSH2_SCP_RESPONSE_BUFLEN 256
8505+
8506+struct _LIBSSH2_SESSION
8507+{
8508+ /* Memory management callbacks */
8509+ void *abstract;
8510+ LIBSSH2_ALLOC_FUNC((*alloc));
8511+ LIBSSH2_REALLOC_FUNC((*realloc));
8512+ LIBSSH2_FREE_FUNC((*free));
8513+
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));
8520+
8521+ /* Method preferences -- NULL yields "load order" */
8522+ char *kex_prefs;
8523+ char *hostkey_prefs;
8524+
8525+ int state;
8526+ int flags;
8527+
8528+ /* Agreed Key Exchange Method */
8529+ const LIBSSH2_KEX_METHOD *kex;
8530+ int burn_optimistic_kexinit:1;
8531+
8532+ unsigned char *session_id;
8533+ unsigned long session_id_len;
8534+
8535+ /* Server's public key */
8536+ const LIBSSH2_HOSTKEY_METHOD *hostkey;
8537+ void *server_hostkey_abstract;
8538+
8539+ /* Either set with libssh2_session_hostkey() (for server mode)
8540+ * Or read from server in (eg) KEXDH_INIT (for client mode)
8541+ */
8542+ unsigned char *server_hostkey;
8543+ unsigned long server_hostkey_len;
8544+#if LIBSSH2_MD5
8545+ unsigned char server_hostkey_md5[MD5_DIGEST_LENGTH];
8546+#endif /* ! LIBSSH2_MD5 */
8547+ unsigned char server_hostkey_sha1[SHA_DIGEST_LENGTH];
8548+
8549+ /* (remote as source of data -- packet_read ) */
8550+ libssh2_endpoint_data remote;
8551+
8552+ /* (local as source of data -- packet_write ) */
8553+ libssh2_endpoint_data local;
8554+
8555+ /* Inbound Data buffer -- Sometimes the packet that comes in isn't the packet we're ready for */
8556+ LIBSSH2_PACKET_BRIGADE packets;
8557+
8558+ /* Active connection channels */
8559+ LIBSSH2_CHANNEL_BRIGADE channels;
8560+ unsigned long next_channel;
8561+
8562+ LIBSSH2_LISTENER *listeners;
8563+
8564+ /* Actual I/O socket */
8565+ int socket_fd;
8566+ int socket_block;
8567+ int socket_state;
8568+ int socket_block_directions;
8569+
8570+ /* Error tracking */
8571+ char *err_msg;
8572+ unsigned long err_msglen;
8573+ int err_should_free;
8574+ int err_code;
8575+
8576+ /* struct members for packet-level reading */
8577+ struct transportpacket packet;
8578+#ifdef LIBSSH2DEBUG
8579+ int showmask; /* what debug/trace messages to display */
8580+#endif
8581+
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;
8586+
8587+ /* State variables used in libssh2_kexinit() */
8588+ libssh2_nonblocking_states kexinit_state;
8589+ unsigned char *kexinit_data;
8590+ size_t kexinit_data_len;
8591+
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;
8600+
8601+ /* State variables used in libssh2_session_free() */
8602+ libssh2_nonblocking_states free_state;
8603+
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;
8608+
8609+ /* State variables used in libssh2_packet_read() */
8610+ libssh2_nonblocking_states readPack_state;
8611+ int readPack_encrypted;
8612+
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;
8618+
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;
8627+
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;
8638+
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;
8650+
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;
8666+
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;
8676+
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;
8683+
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;
8690+
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;
8697+
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;
8706+
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;
8712+
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) */
8718+
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
8730+#else
8731+ long scpRecv_size;
8732+#define scpsize_strtol strtol
8733+#endif
8734+ long scpRecv_mtime;
8735+ long scpRecv_atime;
8736+ char *scpRecv_err_msg;
8737+ long scpRecv_err_len;
8738+ LIBSSH2_CHANNEL *scpRecv_channel;
8739+
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;
8749+};
8750+
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
8756+
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)
8761+#else
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
8765+#endif
8766+
8767+/* libssh2 extensible ssh api, ultimately I'd like to allow loading additional methods via .so/.dll */
8768+
8769+struct _LIBSSH2_KEX_METHOD
8770+{
8771+ const char *name;
8772+
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);
8776+
8777+ long flags;
8778+};
8779+
8780+struct _LIBSSH2_HOSTKEY_METHOD
8781+{
8782+ const char *name;
8783+ unsigned long hash_len;
8784+
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);
8799+};
8800+
8801+struct _LIBSSH2_CRYPT_METHOD
8802+{
8803+ const char *name;
8804+
8805+ int blocksize;
8806+
8807+ /* iv and key sizes (-1 for variable length) */
8808+ int iv_len;
8809+ int secret_len;
8810+
8811+ long flags;
8812+
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,
8818+ void **abstract);
8819+ int (*dtor) (LIBSSH2_SESSION * session, void **abstract);
8820+
8821+ _libssh2_cipher_type(algo);
8822+};
8823+
8824+struct _LIBSSH2_COMP_METHOD
8825+{
8826+ const char *name;
8827+
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);
8834+};
8835+
8836+struct _LIBSSH2_MAC_METHOD
8837+{
8838+ const char *name;
8839+
8840+ /* The length of a given MAC packet */
8841+ int mac_len;
8842+
8843+ /* integrity key length */
8844+ int key_len;
8845+
8846+ /* Message Authentication Code Hashing algo */
8847+ int (*init) (LIBSSH2_SESSION * session, unsigned char *key, int *free_key,
8848+ void **abstract);
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);
8854+};
8855+
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,
8866+ ...);
8867+#else
8868+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
8869+/* C99 style */
8870+#define _libssh2_debug(x,y,z, __VA_ARGS__) do {} while (0)
8871+#elif defined(__GNUC__)
8872+/* GNU style */
8873+#define _libssh2_debug(x,y,z,...) do {} while (0)
8874+#else
8875+/* no gcc and not C99, do static and hopefully inline */
8876+static inline void
8877+_libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, ...)
8878+{
8879+}
8880+#endif
8881+#endif
8882+
8883+#ifdef LIBSSH2DEBUG
8884+#define libssh2_error(session, errcode, errmsg, should_free) \
8885+{ \
8886+ if (session->err_msg && session->err_should_free) { \
8887+ LIBSSH2_FREE(session, session->err_msg); \
8888+ } \
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); \
8894+}
8895+
8896+#else /* ! LIBSSH2DEBUG */
8897+
8898+#define libssh2_error(session, errcode, errmsg, should_free) \
8899+{ \
8900+ if (session->err_msg && session->err_should_free) { \
8901+ LIBSSH2_FREE(session, session->err_msg); \
8902+ } \
8903+ session->err_msg = (char *)errmsg; \
8904+ session->err_msglen = strlen(errmsg); \
8905+ session->err_should_free = should_free; \
8906+ session->err_code = errcode; \
8907+}
8908+
8909+#endif /* ! LIBSSH2DEBUG */
8910+
8911+
8912+#define LIBSSH2_SOCKET_UNKNOWN 1
8913+#define LIBSSH2_SOCKET_CONNECTED 0
8914+#define LIBSSH2_SOCKET_DISCONNECTED -1
8915+
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
8922+
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
8931+
8932+#define SSH_MSG_KEXINIT 20
8933+#define SSH_MSG_NEWKEYS 21
8934+
8935+/* diffie-hellman-group1-sha1 */
8936+#define SSH_MSG_KEXDH_INIT 30
8937+#define SSH_MSG_KEXDH_REPLY 31
8938+
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
8945+
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
8951+
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
8959+
8960+/* Channels */
8961+#define SSH_MSG_GLOBAL_REQUEST 80
8962+#define SSH_MSG_REQUEST_SUCCESS 81
8963+#define SSH_MSG_REQUEST_FAILURE 82
8964+
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
8976+
8977+void libssh2_session_shutdown(LIBSSH2_SESSION * session);
8978+
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);
8983+
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);
8987+
8988+
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. */
8992+
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
9001+
9002+libssh2pack_t libssh2_packet_read(LIBSSH2_SESSION * session);
9003+
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);
9009+
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,
9041+ int stream_id);
9042+
9043+/* this is the lib-internal set blocking function */
9044+int _libssh2_session_set_blocking(LIBSSH2_SESSION * session, int blocking);
9045+
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);
9051+
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
9054+
9055+/* pem.c */
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);
9063+
9064+#endif /* LIBSSH2_H */
9065
9066Property changes on: libssh2/src/libssh2_priv.h
9067___________________________________________________________________
9068Added: svn:mime-type
9069 + text/x-c
9070Added: svn:keywords
9071 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
9072Added: cvs2svn:cvs-rev
9073 + 1.1
9074Added: svn:eol-style
9075 + native
9076Added: svn:executable
9077 + *
9078
9079Index: libssh2/src/sftp.c
9080===================================================================
9081--- libssh2/src/sftp.c (.../tags/RELEASE_0_11_0)
9082+++ libssh2/src/sftp.c (.../trunk)
9083@@ -0,0 +1,2358 @@
9084+/* Copyright (c) 2004-2008, Sara Golemon <sarag@libssh2.org>
9085+ * All rights reserved.
9086+ *
9087+ * Redistribution and use in source and binary forms,
9088+ * with or without modification, are permitted provided
9089+ * that the following conditions are met:
9090+ *
9091+ * Redistributions of source code must retain the above
9092+ * copyright notice, this list of conditions and the
9093+ * following disclaimer.
9094+ *
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.
9099+ *
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.
9104+ *
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
9118+ * OF SUCH DAMAGE.
9119+ */
9120+
9121+#include "libssh2_priv.h"
9122+#include "libssh2_sftp.h"
9123+
9124+/* Note: Version 6 was documented at the time of writing
9125+ * However it was marked as "DO NOT IMPLEMENT" due to pending changes
9126+ *
9127+ * This release of libssh2 implements Version 5 with automatic downgrade
9128+ * based on server's declaration
9129+ */
9130+
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
9159+
9160+#define LIBSSH2_SFTP_HANDLE_FILE 0
9161+#define LIBSSH2_SFTP_HANDLE_DIR 1
9162+
9163+/* S_IFREG */
9164+#define LIBSSH2_SFTP_ATTR_PFILETYPE_FILE 0100000
9165+/* S_IFDIR */
9166+#define LIBSSH2_SFTP_ATTR_PFILETYPE_DIR 0040000
9167+
9168+/* {{{ sftp_packet_add
9169+ * Add a packet to the SFTP packet brigade
9170+ */
9171+static int
9172+sftp_packet_add(LIBSSH2_SFTP * sftp, unsigned char *data,
9173+ unsigned long data_len)
9174+{
9175+ LIBSSH2_SESSION *session = sftp->channel->session;
9176+ LIBSSH2_PACKET *packet;
9177+
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));
9181+ if (!packet) {
9182+ libssh2_error(session, LIBSSH2_ERROR_ALLOC,
9183+ "Unable to allocate datablock for SFTP packet", 0);
9184+ return -1;
9185+ }
9186+ memset(packet, 0, sizeof(LIBSSH2_PACKET));
9187+
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;
9196+ } else {
9197+ sftp->packets.head = packet;
9198+ }
9199+ sftp->packets.tail = packet;
9200+
9201+ return 0;
9202+}
9203+
9204+/* }}} */
9205+
9206+/* {{{ sftp_packet_read
9207+ * Frame an SFTP packet off the channel
9208+ */
9209+static int
9210+sftp_packet_read(LIBSSH2_SFTP * sftp)
9211+{
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;
9218+ int rc;
9219+
9220+ _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Waiting for packet");
9221+
9222+
9223+ /* If there was a previous partial, start using it */
9224+ if (sftp->partial_packet) {
9225+
9226+ packet = sftp->partial_packet;
9227+ packet_len = sftp->partial_len;
9228+ packet_received = sftp->partial_received;
9229+ sftp->partial_packet = NULL;
9230+
9231+ _libssh2_debug(session, LIBSSH2_DBG_SFTP,
9232+ "partial read cont, len: %lu", packet_len);
9233+ }
9234+ else {
9235+ rc = libssh2_channel_read_ex(channel, 0, (char *) buffer, 4);
9236+ if (rc == PACKET_EAGAIN) {
9237+ return PACKET_EAGAIN;
9238+ }
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);
9245+ return -1;
9246+ }
9247+
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);
9254+ return -1;
9255+ }
9256+
9257+ packet = LIBSSH2_ALLOC(session, packet_len);
9258+ if (!packet) {
9259+ libssh2_error(session, LIBSSH2_ERROR_ALLOC,
9260+ "Unable to allocate SFTP packet", 0);
9261+ return -1;
9262+ }
9263+
9264+ packet_received = 0;
9265+ }
9266+
9267+ /* Read as much of the packet as we can */
9268+ while (packet_len > packet_received) {
9269+ bytes_received =
9270+ libssh2_channel_read_ex(channel, 0,
9271+ (char *) packet + packet_received,
9272+ packet_len - packet_received);
9273+
9274+ if (bytes_received == PACKET_EAGAIN) {
9275+ /*
9276+ * We received EAGAIN, save what we have and
9277+ * return to EAGAIN to the caller
9278+ */
9279+ sftp->partial_packet = packet;
9280+ sftp->partial_len = packet_len;
9281+ sftp->partial_received = packet_received;
9282+ packet = NULL;
9283+
9284+ return PACKET_EAGAIN;
9285+ }
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);
9290+ return -1;
9291+ }
9292+ packet_received += bytes_received;
9293+ }
9294+
9295+ if (sftp_packet_add(sftp, packet, packet_len)) {
9296+ LIBSSH2_FREE(session, packet);
9297+ return -1;
9298+ }
9299+
9300+ return packet[0];
9301+}
9302+
9303+/* }}} */
9304+
9305+/* {{{ sftp_packet_ask
9306+ * A la libssh2_packet_ask()
9307+ */
9308+static int
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)
9312+{
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;
9317+
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) {
9325+ return -1;
9326+ }
9327+ }
9328+
9329+ match_buf[0] = packet_type;
9330+ if (packet_type == SSH_FXP_VERSION) {
9331+ /* Special consideration when matching VERSION packet */
9332+ match_len = 1;
9333+ } else {
9334+ libssh2_htonu32(match_buf + 1, request_id);
9335+ }
9336+
9337+ while (packet) {
9338+ if (strncmp((char *) packet->data, (char *) match_buf, match_len) == 0) {
9339+ *data = packet->data;
9340+ *data_len = packet->data_len;
9341+
9342+ if (packet->prev) {
9343+ packet->prev->next = packet->next;
9344+ } else {
9345+ sftp->packets.head = packet->next;
9346+ }
9347+
9348+ if (packet->next) {
9349+ packet->next->prev = packet->prev;
9350+ } else {
9351+ sftp->packets.tail = packet->prev;
9352+ }
9353+
9354+ LIBSSH2_FREE(session, packet);
9355+
9356+ return 0;
9357+ }
9358+ packet = packet->next;
9359+ }
9360+ return -1;
9361+}
9362+
9363+/* }}} */
9364+
9365+/* {{{ sftp_packet_require
9366+ * A la libssh2_packet_require
9367+ */
9368+static int
9369+sftp_packet_require(LIBSSH2_SFTP * sftp, unsigned char packet_type,
9370+ unsigned long request_id, unsigned char **data,
9371+ unsigned long *data_len)
9372+{
9373+ LIBSSH2_SESSION *session = sftp->channel->session;
9374+ int ret;
9375+
9376+ _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Requiring %d packet",
9377+ (int) packet_type);
9378+
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 */
9382+ return 0;
9383+ }
9384+
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) {
9390+ return -1;
9391+ }
9392+
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,
9396+ data_len, 0);
9397+ }
9398+ }
9399+
9400+ /* Only reached if the socket died */
9401+ return -1;
9402+}
9403+
9404+/* }}} */
9405+
9406+/* {{{ sftp_packet_requirev
9407+ * Require one of N possible reponses
9408+ */
9409+static int
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)
9414+{
9415+ int i;
9416+ int ret;
9417+
9418+ /* If no timeout is active, start a new one */
9419+ if (sftp->requirev_start == 0) {
9420+ sftp->requirev_start = time(NULL);
9421+ }
9422+
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) {
9427+ /*
9428+ * Set to zero before all returns to say
9429+ * the timeout is not active
9430+ */
9431+ sftp->requirev_start = 0;
9432+ return 0;
9433+ }
9434+ }
9435+
9436+ ret = sftp_packet_read(sftp);
9437+ if ((ret < 0) && (ret != PACKET_EAGAIN)) {
9438+ sftp->requirev_start = 0;
9439+ return -1;
9440+ } else if (ret <= 0) {
9441+ /* prevent busy-looping */
9442+ long left =
9443+ LIBSSH2_READ_TIMEOUT - (time(NULL) - sftp->requirev_start);
9444+
9445+ if (left <= 0) {
9446+ sftp->requirev_start = 0;
9447+ return PACKET_TIMEOUT;
9448+ } else if (sftp->channel->session->socket_block
9449+ && (libssh2_waitsocket(sftp->channel->session, left) <=
9450+ 0)) {
9451+ sftp->requirev_start = 0;
9452+ return PACKET_TIMEOUT;
9453+ } else if (ret == PACKET_EAGAIN) {
9454+ return PACKET_EAGAIN;
9455+ }
9456+ }
9457+ }
9458+
9459+ sftp->requirev_start = 0;
9460+ return -1;
9461+}
9462+
9463+/* }}} */
9464+
9465+/* {{{ libssh2_sftp_attrsize
9466+ * Size that attr will occupy when turned into a bin struct
9467+ */
9468+static int
9469+libssh2_sftp_attrsize(const LIBSSH2_SFTP_ATTRIBUTES * attrs)
9470+{
9471+ int attrsize = 4; /* flags(4) */
9472+
9473+ if (!attrs) {
9474+ return attrsize;
9475+ }
9476+
9477+ if (attrs->flags & LIBSSH2_SFTP_ATTR_SIZE)
9478+ attrsize += 8;
9479+ if (attrs->flags & LIBSSH2_SFTP_ATTR_UIDGID)
9480+ attrsize += 8;
9481+ if (attrs->flags & LIBSSH2_SFTP_ATTR_PERMISSIONS)
9482+ attrsize += 4;
9483+ if (attrs->flags & LIBSSH2_SFTP_ATTR_ACMODTIME)
9484+ attrsize += 8; /* atime + mtime as u32 */
9485+
9486+ return attrsize;
9487+}
9488+
9489+/* }}} */
9490+
9491+/* {{{ libssh2_sftp_attr2bin
9492+ * Populate attributes into an SFTP block
9493+ */
9494+static int
9495+libssh2_sftp_attr2bin(unsigned char *p, const LIBSSH2_SFTP_ATTRIBUTES * attrs)
9496+{
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;
9501+
9502+ /* TODO: When we add SFTP4+ functionality flag_mask can get additional bits */
9503+
9504+ if (!attrs) {
9505+ libssh2_htonu32(s, 0);
9506+ return 4;
9507+ }
9508+
9509+ libssh2_htonu32(s, attrs->flags & flag_mask);
9510+ s += 4;
9511+
9512+ if (attrs->flags & LIBSSH2_SFTP_ATTR_SIZE) {
9513+ libssh2_htonu64(s, attrs->filesize);
9514+ s += 8;
9515+ }
9516+
9517+ if (attrs->flags & LIBSSH2_SFTP_ATTR_UIDGID) {
9518+ libssh2_htonu32(s, attrs->uid);
9519+ s += 4;
9520+ libssh2_htonu32(s, attrs->gid);
9521+ s += 4;
9522+ }
9523+
9524+ if (attrs->flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) {
9525+ libssh2_htonu32(s, attrs->permissions);
9526+ s += 4;
9527+ }
9528+
9529+ if (attrs->flags & LIBSSH2_SFTP_ATTR_ACMODTIME) {
9530+ libssh2_htonu32(s, attrs->atime);
9531+ s += 4;
9532+ libssh2_htonu32(s, attrs->mtime);
9533+ s += 4;
9534+ }
9535+
9536+ return (s - p);
9537+}
9538+
9539+/* }}} */
9540+
9541+/* {{{ libssh2_sftp_bin2attr
9542+ */
9543+static int
9544+libssh2_sftp_bin2attr(LIBSSH2_SFTP_ATTRIBUTES * attrs, const unsigned char *p)
9545+{
9546+ const unsigned char *s = p;
9547+
9548+ memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
9549+ attrs->flags = libssh2_ntohu32(s);
9550+ s += 4;
9551+
9552+ if (attrs->flags & LIBSSH2_SFTP_ATTR_SIZE) {
9553+ attrs->filesize = libssh2_ntohu64(s);
9554+ s += 8;
9555+ }
9556+
9557+ if (attrs->flags & LIBSSH2_SFTP_ATTR_UIDGID) {
9558+ attrs->uid = libssh2_ntohu32(s);
9559+ s += 4;
9560+ attrs->gid = libssh2_ntohu32(s);
9561+ s += 4;
9562+ }
9563+
9564+ if (attrs->flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) {
9565+ attrs->permissions = libssh2_ntohu32(s);
9566+ s += 4;
9567+ }
9568+
9569+ if (attrs->flags & LIBSSH2_SFTP_ATTR_ACMODTIME) {
9570+ attrs->atime = libssh2_ntohu32(s);
9571+ s += 4;
9572+ attrs->mtime = libssh2_ntohu32(s);
9573+ s += 4;
9574+ }
9575+
9576+ return (s - p);
9577+}
9578+
9579+/* }}} */
9580+
9581+/* ************
9582+ * SFTP API *
9583+ ************ */
9584+
9585+LIBSSH2_CHANNEL_CLOSE_FUNC(libssh2_sftp_dtor);
9586+
9587+/* {{{ libssh2_sftp_dtor
9588+ * Shutdown an SFTP stream when the channel closes
9589+ */
9590+LIBSSH2_CHANNEL_CLOSE_FUNC(libssh2_sftp_dtor)
9591+{
9592+ LIBSSH2_SFTP *sftp = (LIBSSH2_SFTP *) (*channel_abstract);
9593+
9594+ (void) session_abstract;
9595+ (void) channel;
9596+
9597+ /* Loop through handles closing them */
9598+ while (sftp->handles) {
9599+ libssh2_sftp_close_handle(sftp->handles);
9600+ }
9601+
9602+ /* Free the partial packet storage for sftp_packet_read */
9603+ if (sftp->partial_packet) {
9604+ LIBSSH2_FREE(session, sftp->partial_packet);
9605+ }
9606+
9607+ /* Free the packet storage for _libssh2_sftp_packet_readdir */
9608+ if (sftp->readdir_packet) {
9609+ LIBSSH2_FREE(session, sftp->readdir_packet);
9610+ }
9611+
9612+ LIBSSH2_FREE(session, sftp);
9613+}
9614+
9615+/* }}} */
9616+
9617+/* {{{ libssh2_sftp_init
9618+ * Startup an SFTP session
9619+ *
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.
9623+ */
9624+LIBSSH2_API LIBSSH2_SFTP *
9625+libssh2_sftp_init(LIBSSH2_SESSION * session)
9626+{
9627+ unsigned char *data, *s;
9628+ unsigned long data_len;
9629+ int rc;
9630+
9631+ if (session->sftpInit_state == libssh2_NB_state_idle) {
9632+ _libssh2_debug(session, LIBSSH2_DBG_SFTP,
9633+ "Initializing SFTP subsystem");
9634+
9635+ session->sftpInit_sftp = NULL;
9636+
9637+ session->sftpInit_state = libssh2_NB_state_created;
9638+ }
9639+
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);
9649+ return NULL;
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;
9655+ return NULL;
9656+ }
9657+ }
9658+
9659+ session->sftpInit_state = libssh2_NB_state_sent;
9660+ }
9661+
9662+ if (session->sftpInit_state == libssh2_NB_state_sent) {
9663+ rc = libssh2_channel_process_startup(session->sftpInit_channel,
9664+ "subsystem",
9665+ sizeof("subsystem") - 1, "sftp",
9666+ strlen("sftp"));
9667+ if (rc == PACKET_EAGAIN) {
9668+ libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
9669+ "Would block to request SFTP subsystem", 0);
9670+ return NULL;
9671+ } else if (rc) {
9672+ libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE,
9673+ "Unable to request SFTP subsystem", 0);
9674+ goto sftp_init_error;
9675+ }
9676+
9677+ session->sftpInit_state = libssh2_NB_state_sent1;
9678+ }
9679+
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);
9686+ return NULL;
9687+ }
9688+
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;
9694+ }
9695+ memset(session->sftpInit_sftp, 0, sizeof(LIBSSH2_SFTP));
9696+ session->sftpInit_sftp->channel = session->sftpInit_channel;
9697+ session->sftpInit_sftp->request_id = 0;
9698+
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);
9702+
9703+ _libssh2_debug(session, LIBSSH2_DBG_SFTP,
9704+ "Sending FXP_INIT packet advertising version %d support",
9705+ (int) LIBSSH2_SFTP_VERSION);
9706+
9707+ session->sftpInit_state = libssh2_NB_state_sent2;
9708+ }
9709+
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);
9716+ return NULL;
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;
9721+ }
9722+
9723+ session->sftpInit_state = libssh2_NB_state_sent3;
9724+ }
9725+
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",
9732+ 0);
9733+ return NULL;
9734+ } else if (rc) {
9735+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
9736+ "Timeout waiting for response from SFTP subsystem", 0);
9737+ goto sftp_init_error;
9738+ }
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;
9743+ }
9744+
9745+ s = data + 1;
9746+ session->sftpInit_sftp->version = libssh2_ntohu32(s);
9747+ s += 4;
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;
9753+ }
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;
9760+
9761+ extname_len = libssh2_ntohu32(s);
9762+ s += 4;
9763+ extension_name = s;
9764+ s += extname_len;
9765+
9766+ extdata_len = libssh2_ntohu32(s);
9767+ s += 4;
9768+ extension_data = s;
9769+ s += extdata_len;
9770+
9771+ /* TODO: Actually process extensions */
9772+ }
9773+ LIBSSH2_FREE(session, data);
9774+
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;
9778+
9779+ session->sftpInit_state = libssh2_NB_state_idle;
9780+ return session->sftpInit_sftp;
9781+
9782+ sftp_init_error:
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;
9788+ }
9789+ session->sftpInit_state = libssh2_NB_state_idle;
9790+ return NULL;
9791+}
9792+
9793+/* }}} */
9794+
9795+/* {{{ libssh2_sftp_shutdown
9796+ * Shutsdown the SFTP subsystem
9797+ */
9798+LIBSSH2_API int
9799+libssh2_sftp_shutdown(LIBSSH2_SFTP * sftp)
9800+{
9801+ /*
9802+ * Make sure all memory used in the state variables are free
9803+ */
9804+ if (sftp->partial_packet) {
9805+ LIBSSH2_FREE(sftp->channel->session, sftp->partial_packet);
9806+ sftp->partial_packet = NULL;
9807+ }
9808+ if (sftp->open_packet) {
9809+ LIBSSH2_FREE(sftp->channel->session, sftp->open_packet);
9810+ sftp->open_packet = NULL;
9811+ }
9812+ if (sftp->readdir_packet) {
9813+ LIBSSH2_FREE(sftp->channel->session, sftp->readdir_packet);
9814+ sftp->readdir_packet = NULL;
9815+ }
9816+ if (sftp->write_packet) {
9817+ LIBSSH2_FREE(sftp->channel->session, sftp->write_packet);
9818+ sftp->write_packet = NULL;
9819+ }
9820+ if (sftp->fstat_packet) {
9821+ LIBSSH2_FREE(sftp->channel->session, sftp->fstat_packet);
9822+ sftp->fstat_packet = NULL;
9823+ }
9824+ if (sftp->unlink_packet) {
9825+ LIBSSH2_FREE(sftp->channel->session, sftp->unlink_packet);
9826+ sftp->unlink_packet = NULL;
9827+ }
9828+ if (sftp->rename_packet) {
9829+ LIBSSH2_FREE(sftp->channel->session, sftp->rename_packet);
9830+ sftp->rename_packet = NULL;
9831+ }
9832+ if (sftp->mkdir_packet) {
9833+ LIBSSH2_FREE(sftp->channel->session, sftp->mkdir_packet);
9834+ sftp->mkdir_packet = NULL;
9835+ }
9836+ if (sftp->rmdir_packet) {
9837+ LIBSSH2_FREE(sftp->channel->session, sftp->rmdir_packet);
9838+ sftp->rmdir_packet = NULL;
9839+ }
9840+ if (sftp->stat_packet) {
9841+ LIBSSH2_FREE(sftp->channel->session, sftp->stat_packet);
9842+ sftp->stat_packet = NULL;
9843+ }
9844+ if (sftp->symlink_packet) {
9845+ LIBSSH2_FREE(sftp->channel->session, sftp->symlink_packet);
9846+ sftp->symlink_packet = NULL;
9847+ }
9848+
9849+ return libssh2_channel_free(sftp->channel);
9850+}
9851+
9852+/* }}} */
9853+
9854+/* *******************************
9855+ * SFTP File and Directory Ops *
9856+ ******************************* */
9857+
9858+/* {{{ libssh2_sftp_open_ex
9859+ */
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,
9863+ int open_type)
9864+{
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
9870+ };
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 };
9875+ int rc;
9876+
9877+ if (sftp->open_state == libssh2_NB_state_idle) {
9878+ /* packet_len(4) + packet_type(1) + request_id(4) + filename_len(4) +
9879+ flags(4) */
9880+ sftp->open_packet_len = filename_len + 13 +
9881+ ((open_type ==
9882+ LIBSSH2_SFTP_OPENFILE) ? (4 +
9883+ libssh2_sftp_attrsize(&attrs)) : 0);
9884+
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",
9890+ 0);
9891+ return NULL;
9892+ }
9893+ /* Filetype in SFTP 3 and earlier */
9894+ attrs.permissions = mode |
9895+ ((open_type ==
9896+ LIBSSH2_SFTP_OPENFILE) ? LIBSSH2_SFTP_ATTR_PFILETYPE_FILE :
9897+ LIBSSH2_SFTP_ATTR_PFILETYPE_DIR);
9898+
9899+ libssh2_htonu32(s, sftp->open_packet_len - 4);
9900+ s += 4;
9901+ *(s++) =
9902+ (open_type ==
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);
9906+ s += 4;
9907+ libssh2_htonu32(s, filename_len);
9908+ s += 4;
9909+ memcpy(s, filename, filename_len);
9910+ s += filename_len;
9911+ if (open_type == LIBSSH2_SFTP_OPENFILE) {
9912+ libssh2_htonu32(s, flags);
9913+ s += 4;
9914+ s += libssh2_sftp_attr2bin(s, &attrs);
9915+ }
9916+
9917+ _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Sending %s open request",
9918+ (open_type ==
9919+ LIBSSH2_SFTP_OPENFILE) ? "file" : "directory");
9920+
9921+ sftp->open_state = libssh2_NB_state_created;
9922+ }
9923+
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",
9930+ 0);
9931+ return NULL;
9932+ }
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! */
9936+
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;
9942+ return NULL;
9943+ }
9944+ LIBSSH2_FREE(session, sftp->open_packet);
9945+ sftp->open_packet = NULL;
9946+
9947+ sftp->open_state = libssh2_NB_state_sent;
9948+ }
9949+
9950+ if (sftp->open_state == libssh2_NB_state_sent) {
9951+ rc = sftp_packet_requirev(sftp, 2, fopen_responses,
9952+ sftp->open_request_id, &data,
9953+ &data_len);
9954+ if (rc == PACKET_EAGAIN) {
9955+ libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
9956+ "Would block waiting for status message", 0);
9957+ return NULL;
9958+ }
9959+ else if (rc) {
9960+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
9961+ "Timeout waiting for status message", 0);
9962+ sftp->open_state = libssh2_NB_state_idle;
9963+ return NULL;
9964+ }
9965+ }
9966+
9967+ sftp->open_state = libssh2_NB_state_idle;
9968+
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) {
9974+ int badness = 1;
9975+ sftp->last_errno = libssh2_ntohu32(data + 5);
9976+
9977+ if(LIBSSH2_FX_OK == sftp->last_errno) {
9978+ _libssh2_debug(session, LIBSSH2_DBG_SFTP, "got HANDLE FXOK!");
9979+
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;
9986+ return NULL;
9987+ }
9988+ else if(!rc)
9989+ /* we got the handle so this is not a bad situation */
9990+ badness = 0;
9991+ }
9992+
9993+ if(badness) {
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);
9999+ return NULL;
10000+ }
10001+ }
10002+
10003+ fp = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_SFTP_HANDLE));
10004+ if (!fp) {
10005+ libssh2_error(session, LIBSSH2_ERROR_ALLOC,
10006+ "Unable to allocate new SFTP handle structure", 0);
10007+ LIBSSH2_FREE(session, data);
10008+ return NULL;
10009+ }
10010+ memset(fp, 0, sizeof(LIBSSH2_SFTP_HANDLE));
10011+ fp->handle_type =
10012+ (open_type ==
10013+ LIBSSH2_SFTP_OPENFILE) ? LIBSSH2_SFTP_HANDLE_FILE :
10014+ LIBSSH2_SFTP_HANDLE_DIR;
10015+
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;
10020+ }
10021+
10022+ memcpy(fp->handle, data + 9, fp->handle_len);
10023+ LIBSSH2_FREE(session, data);
10024+
10025+ /* Link the file and the sftp session together */
10026+ fp->next = sftp->handles;
10027+ if (fp->next) {
10028+ fp->next->prev = fp;
10029+ }
10030+ fp->sftp = sftp;
10031+
10032+ fp->u.file.offset = 0;
10033+
10034+ _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Open command successful");
10035+ return fp;
10036+}
10037+
10038+/* }}} */
10039+
10040+/* {{{ libssh2_sftp_read
10041+ * Read from an SFTP file handle
10042+ */
10043+LIBSSH2_API ssize_t
10044+libssh2_sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer,
10045+ size_t buffer_maxlen)
10046+{
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;
10060+ int retcode;
10061+
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;
10068+ } else {
10069+ packet = sftp->read_packet;
10070+ request_id = sftp->read_request_id;
10071+ total_read = sftp->read_total_read;
10072+ }
10073+
10074+ while (total_read < buffer_maxlen) {
10075+ s = packet;
10076+ /*
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.
10080+ */
10081+ bytes_requested = buffer_maxlen - total_read;
10082+ /* 10 = packet_type(1) + request_id(4) + data_length(4) +
10083+ end_of_line_flag(1)
10084+
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
10088+ this trick.
10089+
10090+ Further details on this issue:
10091+
10092+ https://sourceforge.net/mailarchive/forum.php?thread_name=9c3275a90811261517v6c0b1da2u918cc1b8370abf83%40mail.gmail.com&forum_name=libssh2-devel
10093+
10094+ http://forums.globalscape.com/tm.aspx?m=15249
10095+
10096+ */
10097+ if (bytes_requested > LIBSSH2_SFTP_PACKET_MAXLEN - 13) {
10098+ bytes_requested = LIBSSH2_SFTP_PACKET_MAXLEN - 13;
10099+ }
10100+#ifdef LIBSSH2_DEBUG_SFTP
10101+ _libssh2_debug(session, LIBSSH2_DBG_SFTP,
10102+ "Requesting %lu bytes from SFTP handle",
10103+ (unsigned long) bytes_requested);
10104+#endif
10105+
10106+ if (sftp->read_state == libssh2_NB_state_allocated) {
10107+ libssh2_htonu32(s, packet_len - 4);
10108+ s += 4;
10109+ *(s++) = SSH_FXP_READ;
10110+ request_id = sftp->request_id++;
10111+ libssh2_htonu32(s, request_id);
10112+ s += 4;
10113+ libssh2_htonu32(s, handle->handle_len);
10114+ s += 4;
10115+
10116+ memcpy(s, handle->handle, handle->handle_len);
10117+ s += handle->handle_len;
10118+
10119+ libssh2_htonu64(s, handle->u.file.offset);
10120+ s += 8;
10121+
10122+ libssh2_htonu32(s, bytes_requested);
10123+ s += 4;
10124+
10125+ sftp->read_state = libssh2_NB_state_created;
10126+ }
10127+
10128+ if (sftp->read_state == libssh2_NB_state_created) {
10129+ retcode =
10130+ libssh2_channel_write_ex(channel, 0, (char *) packet,
10131+ packet_len);
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;
10144+ return -1;
10145+ }
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;
10150+ }
10151+
10152+ if (sftp->read_state == libssh2_NB_state_sent) {
10153+ retcode =
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;
10163+ return -1;
10164+ }
10165+
10166+ sftp->read_state = libssh2_NB_state_sent1;
10167+ }
10168+
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;
10175+
10176+ if (retcode == LIBSSH2_FX_EOF) {
10177+ return total_read;
10178+ } else {
10179+ sftp->last_errno = retcode;
10180+ libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
10181+ "SFTP Protocol Error", 0);
10182+ return -1;
10183+ }
10184+
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;
10190+ return -1;
10191+ }
10192+#ifdef LIBSSH2_DEBUG_SFTP
10193+ _libssh2_debug(session, LIBSSH2_DBG_SFTP, "%lu bytes returned",
10194+ (unsigned long) bytes_read);
10195+#endif
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);
10200+ /*
10201+ * Set the state back to allocated, so a new one will be
10202+ * created to either request more data or get EOF
10203+ */
10204+ sftp->read_state = libssh2_NB_state_allocated;
10205+ }
10206+ }
10207+
10208+ sftp->read_packet = NULL;
10209+ sftp->read_state = libssh2_NB_state_idle;
10210+ return total_read;
10211+}
10212+
10213+/* }}} */
10214+
10215+/* {{{ libssh2_sftp_readdir
10216+ * Read from an SFTP directory handle
10217+ */
10218+LIBSSH2_API int
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)
10223+{
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 };
10233+ int retcode;
10234+
10235+ if (sftp->readdir_state == libssh2_NB_state_idle) {
10236+ if (handle->u.dir.names_left) {
10237+ /*
10238+ * A prior request returned more than one directory entry,
10239+ * feed it back from the buffer
10240+ */
10241+ unsigned char *s = (unsigned char *) handle->u.dir.next_name;
10242+ unsigned long real_filename_len = libssh2_ntohu32(s);
10243+
10244+ filename_len = real_filename_len;
10245+ s += 4;
10246+ if (filename_len > buffer_maxlen) {
10247+ filename_len = buffer_maxlen;
10248+ }
10249+ memcpy(buffer, s, filename_len);
10250+ s += real_filename_len;
10251+
10252+ /* The filename is not null terminated, make it so if possible */
10253+ if (filename_len < buffer_maxlen) {
10254+ buffer[filename_len] = '\0';
10255+ }
10256+
10257+ if ((longentry == NULL) || (longentry_maxlen == 0)) {
10258+ /* Skip longname */
10259+ s += 4 + libssh2_ntohu32(s);
10260+ } else {
10261+ unsigned long real_longentry_len = libssh2_ntohu32(s);
10262+
10263+ longentry_len = real_longentry_len;
10264+ s += 4;
10265+ if (longentry_len > longentry_maxlen) {
10266+ longentry_len = longentry_maxlen;
10267+ }
10268+ memcpy(longentry, s, longentry_len);
10269+ s += real_longentry_len;
10270+
10271+ /* The longentry is not null terminated, make it so if possible */
10272+ if (longentry_len < longentry_maxlen) {
10273+ longentry[longentry_len] = '\0';
10274+ }
10275+ }
10276+
10277+ if (attrs) {
10278+ memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
10279+ }
10280+ s += libssh2_sftp_bin2attr(attrs ? attrs : &attrs_dummy, s);
10281+
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);
10285+ }
10286+
10287+ _libssh2_debug(session, LIBSSH2_DBG_SFTP,
10288+ "libssh2_sftp_readdir_ex() return %d",
10289+ filename_len);
10290+ return filename_len;
10291+ }
10292+
10293+ /* Request another entry(entries?) */
10294+
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",
10299+ 0);
10300+ return -1;
10301+ }
10302+
10303+ libssh2_htonu32(s, packet_len - 4);
10304+ s += 4;
10305+ *(s++) = SSH_FXP_READDIR;
10306+ sftp->readdir_request_id = sftp->request_id++;
10307+ libssh2_htonu32(s, sftp->readdir_request_id);
10308+ s += 4;
10309+ libssh2_htonu32(s, handle->handle_len);
10310+ s += 4;
10311+ memcpy(s, handle->handle, handle->handle_len);
10312+ s += handle->handle_len;
10313+
10314+ sftp->readdir_state = libssh2_NB_state_created;
10315+ }
10316+
10317+ if (sftp->readdir_state == libssh2_NB_state_created) {
10318+ _libssh2_debug(session, LIBSSH2_DBG_SFTP,
10319+ "Reading entries from directory handle");
10320+ if ((retcode =
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;
10331+ return -1;
10332+ }
10333+
10334+ LIBSSH2_FREE(session, sftp->readdir_packet);
10335+ sftp->readdir_packet = NULL;
10336+
10337+ sftp->readdir_state = libssh2_NB_state_sent;
10338+ }
10339+
10340+ retcode =
10341+ sftp_packet_requirev(sftp, 2, read_responses,
10342+ sftp->readdir_request_id, &data,
10343+ &data_len);
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;
10350+ return -1;
10351+ }
10352+
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;
10358+ return 0;
10359+ } else {
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;
10364+ return -1;
10365+ }
10366+ }
10367+
10368+ num_names = libssh2_ntohu32(data + 5);
10369+ _libssh2_debug(session, LIBSSH2_DBG_SFTP, "%lu entries returned",
10370+ num_names);
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;
10375+ }
10376+
10377+ if (num_names == 1) {
10378+ unsigned long real_filename_len = libssh2_ntohu32(data + 9);
10379+
10380+ filename_len = real_filename_len;
10381+ if (filename_len > buffer_maxlen) {
10382+ filename_len = buffer_maxlen;
10383+ }
10384+ memcpy(buffer, data + 13, filename_len);
10385+
10386+ /* The filename is not null terminated, make it so if possible */
10387+ if (filename_len < buffer_maxlen) {
10388+ buffer[filename_len] = '\0';
10389+ }
10390+
10391+ if (attrs) {
10392+ memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
10393+ libssh2_sftp_bin2attr(attrs, data + 13 + real_filename_len +
10394+ (4 +
10395+ libssh2_ntohu32(data + 13 +
10396+ real_filename_len)));
10397+ }
10398+ LIBSSH2_FREE(session, data);
10399+
10400+ sftp->readdir_state = libssh2_NB_state_idle;
10401+ return filename_len;
10402+ }
10403+
10404+ handle->u.dir.names_left = num_names;
10405+ handle->u.dir.names_packet = data;
10406+ handle->u.dir.next_name = (char *) data + 9;
10407+
10408+ sftp->readdir_state = libssh2_NB_state_idle;
10409+
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);
10413+}
10414+
10415+/* }}} */
10416+
10417+/* {{{ libssh2_sftp_write
10418+ * Write data to a file handle
10419+ */
10420+LIBSSH2_API ssize_t
10421+libssh2_sftp_write(LIBSSH2_SFTP_HANDLE * handle, const char *buffer,
10422+ size_t count)
10423+{
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;
10432+ int rc;
10433+
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);
10441+ return -1;
10442+ }
10443+
10444+ libssh2_htonu32(s, packet_len - 4);
10445+ s += 4;
10446+ *(s++) = SSH_FXP_WRITE;
10447+ sftp->write_request_id = sftp->request_id++;
10448+ libssh2_htonu32(s, sftp->write_request_id);
10449+ s += 4;
10450+ libssh2_htonu32(s, handle->handle_len);
10451+ s += 4;
10452+ memcpy(s, handle->handle, handle->handle_len);
10453+ s += handle->handle_len;
10454+ libssh2_htonu64(s, handle->u.file.offset);
10455+ s += 8;
10456+ libssh2_htonu32(s, count);
10457+ s += 4;
10458+ memcpy(s, buffer, count);
10459+ s += count;
10460+
10461+ sftp->write_state = libssh2_NB_state_created;
10462+ }
10463+
10464+ if (sftp->write_state == libssh2_NB_state_created) {
10465+ if ((rc =
10466+ libssh2_channel_write_ex(channel, 0, (char *) sftp->write_packet,
10467+ packet_len)) == PACKET_EAGAIN) {
10468+ return PACKET_EAGAIN;
10469+ }
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;
10476+ return -1;
10477+ }
10478+ LIBSSH2_FREE(session, sftp->write_packet);
10479+ sftp->write_packet = NULL;
10480+ sftp->write_state = libssh2_NB_state_sent;
10481+ }
10482+
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;
10487+ } else if (rc) {
10488+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
10489+ "Timeout waiting for status message", 0);
10490+ sftp->write_state = libssh2_NB_state_idle;
10491+ return -1;
10492+ }
10493+
10494+ sftp->write_state = libssh2_NB_state_idle;
10495+
10496+ retcode = libssh2_ntohu32(data + 5);
10497+ LIBSSH2_FREE(session, data);
10498+
10499+ if (retcode == LIBSSH2_FX_OK) {
10500+ handle->u.file.offset += count;
10501+ return count;
10502+ }
10503+ libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error",
10504+ 0);
10505+ sftp->last_errno = retcode;
10506+
10507+ return -1;
10508+}
10509+
10510+/* }}} */
10511+
10512+/* {{{ libssh2_sftp_fstat_ex
10513+ * Get or Set stat on a file
10514+ */
10515+LIBSSH2_API int
10516+libssh2_sftp_fstat_ex(LIBSSH2_SFTP_HANDLE * handle,
10517+ LIBSSH2_SFTP_ATTRIBUTES * attrs, int setstat)
10518+{
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 };
10529+ int rc;
10530+
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",
10538+ 0);
10539+ return -1;
10540+ }
10541+
10542+ libssh2_htonu32(s, packet_len - 4);
10543+ s += 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);
10547+ s += 4;
10548+ libssh2_htonu32(s, handle->handle_len);
10549+ s += 4;
10550+ memcpy(s, handle->handle, handle->handle_len);
10551+ s += handle->handle_len;
10552+ if (setstat) {
10553+ s += libssh2_sftp_attr2bin(s, attrs);
10554+ }
10555+
10556+ sftp->fstat_state = libssh2_NB_state_created;
10557+ }
10558+
10559+ if (sftp->fstat_state == libssh2_NB_state_created) {
10560+ rc = libssh2_channel_write_ex(channel, 0, (char *) sftp->fstat_packet,
10561+ packet_len);
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;
10571+ return -1;
10572+ }
10573+ LIBSSH2_FREE(session, sftp->fstat_packet);
10574+ sftp->fstat_packet = NULL;
10575+
10576+ sftp->fstat_state = libssh2_NB_state_sent;
10577+ }
10578+
10579+ rc = sftp_packet_requirev(sftp, 2, fstat_responses,
10580+ sftp->fstat_request_id, &data,
10581+ &data_len);
10582+ if (rc == PACKET_EAGAIN) {
10583+ return PACKET_EAGAIN;
10584+ } else if (rc) {
10585+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
10586+ "Timeout waiting for status message", 0);
10587+ sftp->fstat_state = libssh2_NB_state_idle;
10588+ return -1;
10589+ }
10590+
10591+ sftp->fstat_state = libssh2_NB_state_idle;
10592+
10593+ if (data[0] == SSH_FXP_STATUS) {
10594+ int retcode;
10595+
10596+ retcode = libssh2_ntohu32(data + 5);
10597+ LIBSSH2_FREE(session, data);
10598+ if (retcode == LIBSSH2_FX_OK) {
10599+ return 0;
10600+ } else {
10601+ sftp->last_errno = retcode;
10602+ libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
10603+ "SFTP Protocol Error", 0);
10604+ return -1;
10605+ }
10606+ }
10607+
10608+ libssh2_sftp_bin2attr(attrs, data + 5);
10609+
10610+ return 0;
10611+}
10612+
10613+/* }}} */
10614+
10615+/* {{{ libssh2_sftp_seek
10616+ * Set the read/write pointer to an arbitrary position within the file
10617+ */
10618+LIBSSH2_API void
10619+libssh2_sftp_seek(LIBSSH2_SFTP_HANDLE * handle, size_t offset)
10620+{
10621+ handle->u.file.offset = offset;
10622+}
10623+
10624+/* }}} */
10625+
10626+/* {{{ libssh2_sftp_seek64
10627+ * Set the read/write pointer to an arbitrary position within the file
10628+ */
10629+LIBSSH2_API void
10630+libssh2_sftp_seek64(LIBSSH2_SFTP_HANDLE * handle, libssh2_uint64_t offset)
10631+{
10632+ handle->u.file.offset = offset;
10633+}
10634+
10635+/* }}} */
10636+
10637+/* {{{ libssh2_sftp_tell
10638+ * Return the current read/write pointer's offset
10639+ */
10640+LIBSSH2_API size_t
10641+libssh2_sftp_tell(LIBSSH2_SFTP_HANDLE * handle)
10642+{
10643+ return handle->u.file.offset;
10644+}
10645+
10646+/* {{{ libssh2_sftp_tell64
10647+ * Return the current read/write pointer's offset
10648+ */
10649+LIBSSH2_API libssh2_uint64_t
10650+libssh2_sftp_tell64(LIBSSH2_SFTP_HANDLE * handle)
10651+{
10652+ return handle->u.file.offset;
10653+}
10654+
10655+/* }}} */
10656+
10657+
10658+/* {{{ libssh2_sftp_close_handle
10659+ * Close a file or directory handle
10660+ * Also frees handle resource and unlinks it from the SFTP structure
10661+ */
10662+LIBSSH2_API int
10663+libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE * handle)
10664+{
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;
10672+ int rc;
10673+
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);
10680+ return -1;
10681+ }
10682+
10683+ libssh2_htonu32(s, packet_len - 4);
10684+ s += 4;
10685+ *(s++) = SSH_FXP_CLOSE;
10686+ handle->close_request_id = sftp->request_id++;
10687+ libssh2_htonu32(s, handle->close_request_id);
10688+ s += 4;
10689+ libssh2_htonu32(s, handle->handle_len);
10690+ s += 4;
10691+ memcpy(s, handle->handle, handle->handle_len);
10692+ s += handle->handle_len;
10693+
10694+ handle->close_state = libssh2_NB_state_created;
10695+ }
10696+
10697+ if (handle->close_state == libssh2_NB_state_created) {
10698+ rc = libssh2_channel_write_ex(channel, 0,
10699+ (char *) handle->close_packet,
10700+ packet_len);
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;
10709+ return -1;
10710+ }
10711+ LIBSSH2_FREE(session, handle->close_packet);
10712+ handle->close_packet = NULL;
10713+
10714+ handle->close_state = libssh2_NB_state_sent;
10715+ }
10716+
10717+ if (handle->close_state == libssh2_NB_state_sent) {
10718+ rc = sftp_packet_require(sftp, SSH_FXP_STATUS,
10719+ handle->close_request_id, &data,
10720+ &data_len);
10721+ if (rc == PACKET_EAGAIN) {
10722+ return PACKET_EAGAIN;
10723+ } else if (rc) {
10724+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
10725+ "Timeout waiting for status message", 0);
10726+ handle->close_state = libssh2_NB_state_idle;
10727+ return -1;
10728+ }
10729+
10730+ handle->close_state = libssh2_NB_state_sent1;
10731+ }
10732+
10733+ retcode = libssh2_ntohu32(data + 5);
10734+ LIBSSH2_FREE(session, data);
10735+
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;
10741+ return -1;
10742+ }
10743+
10744+ if (handle == sftp->handles) {
10745+ sftp->handles = handle->next;
10746+ }
10747+ if (handle->next) {
10748+ handle->next->prev = NULL;
10749+ }
10750+
10751+ if ((handle->handle_type == LIBSSH2_SFTP_HANDLE_DIR)
10752+ && handle->u.dir.names_left) {
10753+ LIBSSH2_FREE(session, handle->u.dir.names_packet);
10754+ }
10755+
10756+ handle->close_state = libssh2_NB_state_idle;
10757+
10758+ LIBSSH2_FREE(session, handle);
10759+
10760+ return 0;
10761+}
10762+
10763+/* }}} */
10764+
10765+/* **********************
10766+ * SFTP Miscellaneous *
10767+ ********************** */
10768+
10769+/* {{{ libssh2_sftp_unlink_ex
10770+ * Delete a file from the remote server
10771+ */
10772+/* libssh2_sftp_unlink_ex - NB-UNSAFE?? */
10773+LIBSSH2_API int
10774+libssh2_sftp_unlink_ex(LIBSSH2_SFTP * sftp, const char *filename,
10775+ unsigned int filename_len)
10776+{
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;
10783+ int rc;
10784+
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",
10791+ 0);
10792+ return -1;
10793+ }
10794+
10795+ libssh2_htonu32(s, packet_len - 4);
10796+ s += 4;
10797+ *(s++) = SSH_FXP_REMOVE;
10798+ sftp->unlink_request_id = sftp->request_id++;
10799+ libssh2_htonu32(s, sftp->unlink_request_id);
10800+ s += 4;
10801+ libssh2_htonu32(s, filename_len);
10802+ s += 4;
10803+ memcpy(s, filename, filename_len);
10804+ s += filename_len;
10805+
10806+ sftp->unlink_state = libssh2_NB_state_created;
10807+ }
10808+
10809+ if (sftp->unlink_state == libssh2_NB_state_created) {
10810+ rc = libssh2_channel_write_ex(channel, 0, (char *) sftp->unlink_packet,
10811+ packet_len);
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;
10820+ return -1;
10821+ }
10822+ LIBSSH2_FREE(session, sftp->unlink_packet);
10823+ sftp->unlink_packet = NULL;
10824+
10825+ sftp->unlink_state = libssh2_NB_state_sent;
10826+ }
10827+
10828+ rc = sftp_packet_require(sftp, SSH_FXP_STATUS,
10829+ sftp->unlink_request_id, &data,
10830+ &data_len);
10831+ if (rc == PACKET_EAGAIN) {
10832+ return PACKET_EAGAIN;
10833+ }
10834+ else if (rc) {
10835+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
10836+ "Timeout waiting for status message", 0);
10837+ sftp->unlink_state = libssh2_NB_state_idle;
10838+ return -1;
10839+ }
10840+
10841+ sftp->unlink_state = libssh2_NB_state_idle;
10842+
10843+ retcode = libssh2_ntohu32(data + 5);
10844+ LIBSSH2_FREE(session, data);
10845+
10846+ if (retcode == LIBSSH2_FX_OK) {
10847+ return 0;
10848+ } else {
10849+ sftp->last_errno = retcode;
10850+ libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
10851+ "SFTP Protocol Error", 0);
10852+ return -1;
10853+ }
10854+}
10855+
10856+/* }}} */
10857+
10858+/* {{{ libssh2_sftp_rename_ex
10859+ * Rename a file on the remote server
10860+ */
10861+LIBSSH2_API int
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)
10866+{
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 >=
10872+ 5 ? 4 : 0);
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;
10876+ int rc;
10877+
10878+ if (sftp->version < 2) {
10879+ libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
10880+ "Server does not support RENAME", 0);
10881+ return -1;
10882+ }
10883+
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",
10892+ 0);
10893+ return -1;
10894+ }
10895+
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;
10910+
10911+ if (sftp->version >= 5) {
10912+ libssh2_htonu32(sftp->rename_s, flags);
10913+ sftp->rename_s += 4;
10914+ }
10915+
10916+ sftp->rename_state = libssh2_NB_state_created;
10917+ }
10918+
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;
10930+ return -1;
10931+ }
10932+ LIBSSH2_FREE(session, sftp->rename_packet);
10933+ sftp->rename_packet = NULL;
10934+
10935+ sftp->rename_state = libssh2_NB_state_sent;
10936+ }
10937+
10938+ rc = sftp_packet_require(sftp, SSH_FXP_STATUS,
10939+ sftp->rename_request_id, &data,
10940+ &data_len);
10941+ if (rc == PACKET_EAGAIN) {
10942+ return PACKET_EAGAIN;
10943+ } else if (rc) {
10944+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
10945+ "Timeout waiting for status message", 0);
10946+ sftp->rename_state = libssh2_NB_state_idle;
10947+ return -1;
10948+ }
10949+
10950+ sftp->rename_state = libssh2_NB_state_idle;
10951+
10952+ retcode = libssh2_ntohu32(data + 5);
10953+ LIBSSH2_FREE(session, data);
10954+
10955+ switch (retcode) {
10956+ case LIBSSH2_FX_OK:
10957+ retcode = 0;
10958+ break;
10959+
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",
10963+ 0);
10964+ sftp->last_errno = retcode;
10965+ retcode = -1;
10966+ break;
10967+
10968+ case LIBSSH2_FX_OP_UNSUPPORTED:
10969+ libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
10970+ "Operation Not Supported", 0);
10971+ sftp->last_errno = retcode;
10972+ retcode = -1;
10973+ break;
10974+
10975+ default:
10976+ libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
10977+ "SFTP Protocol Error", 0);
10978+ sftp->last_errno = retcode;
10979+ retcode = -1;
10980+ }
10981+
10982+ return retcode;
10983+}
10984+
10985+/* }}} */
10986+
10987+/* {{{ libssh2_sftp_mkdir_ex
10988+ * Create an SFTP directory
10989+ */
10990+LIBSSH2_API int
10991+libssh2_sftp_mkdir_ex(LIBSSH2_SFTP * sftp, const char *path,
10992+ unsigned int path_len, long mode)
10993+{
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
10998+ };
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;
11003+ int rc;
11004+
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);
11009+ if (!packet) {
11010+ libssh2_error(session, LIBSSH2_ERROR_ALLOC,
11011+ "Unable to allocate memory for FXP_MKDIR packet", 0);
11012+ return -1;
11013+ }
11014+ /* Filetype in SFTP 3 and earlier */
11015+ attrs.permissions = mode | LIBSSH2_SFTP_ATTR_PFILETYPE_DIR;
11016+
11017+ libssh2_htonu32(s, packet_len - 4);
11018+ s += 4;
11019+ *(s++) = SSH_FXP_MKDIR;
11020+ request_id = sftp->request_id++;
11021+ libssh2_htonu32(s, request_id);
11022+ s += 4;
11023+ libssh2_htonu32(s, path_len);
11024+ s += 4;
11025+ memcpy(s, path, path_len);
11026+ s += path_len;
11027+ s += libssh2_sftp_attr2bin(s, &attrs);
11028+
11029+ sftp->mkdir_state = libssh2_NB_state_created;
11030+ } else {
11031+ packet = sftp->mkdir_packet;
11032+ request_id = sftp->mkdir_request_id;
11033+ }
11034+
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;
11041+ }
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;
11047+ return -1;
11048+ }
11049+ LIBSSH2_FREE(session, packet);
11050+ sftp->mkdir_state = libssh2_NB_state_sent;
11051+ sftp->mkdir_packet = NULL;
11052+ }
11053+
11054+ rc = sftp_packet_require(sftp, SSH_FXP_STATUS, request_id, &data,
11055+ &data_len);
11056+ if (rc == PACKET_EAGAIN) {
11057+ return PACKET_EAGAIN;
11058+ } else if (rc) {
11059+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
11060+ "Timeout waiting for status message", 0);
11061+ sftp->mkdir_state = libssh2_NB_state_idle;
11062+ return -1;
11063+ }
11064+
11065+ sftp->mkdir_state = libssh2_NB_state_idle;
11066+
11067+ retcode = libssh2_ntohu32(data + 5);
11068+ LIBSSH2_FREE(session, data);
11069+
11070+ if (retcode == LIBSSH2_FX_OK) {
11071+ return 0;
11072+ } else {
11073+ libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
11074+ "SFTP Protocol Error", 0);
11075+ sftp->last_errno = retcode;
11076+ return -1;
11077+ }
11078+}
11079+
11080+/* }}} */
11081+
11082+/* {{{ libssh2_sftp_rmdir_ex
11083+ * Remove a directory
11084+ */
11085+/* libssh2_sftp_rmdir_ex - NB-UNSAFE?? */
11086+LIBSSH2_API int
11087+libssh2_sftp_rmdir_ex(LIBSSH2_SFTP * sftp, const char *path,
11088+ unsigned int path_len)
11089+{
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;
11096+ int rc;
11097+
11098+ if (sftp->rmdir_state == libssh2_NB_state_idle) {
11099+ _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Removing directory: %s",
11100+ path);
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);
11105+ return -1;
11106+ }
11107+
11108+ libssh2_htonu32(s, packet_len - 4);
11109+ s += 4;
11110+ *(s++) = SSH_FXP_RMDIR;
11111+ sftp->rmdir_request_id = sftp->request_id++;
11112+ libssh2_htonu32(s, sftp->rmdir_request_id);
11113+ s += 4;
11114+ libssh2_htonu32(s, path_len);
11115+ s += 4;
11116+ memcpy(s, path, path_len);
11117+ s += path_len;
11118+
11119+ sftp->rmdir_state = libssh2_NB_state_created;
11120+ }
11121+
11122+ if (sftp->rmdir_state == libssh2_NB_state_created) {
11123+ rc = libssh2_channel_write_ex(channel, 0, (char *) sftp->rmdir_packet,
11124+ packet_len);
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;
11133+ return -1;
11134+ }
11135+ LIBSSH2_FREE(session, sftp->rmdir_packet);
11136+ sftp->rmdir_packet = NULL;
11137+
11138+ sftp->rmdir_state = libssh2_NB_state_sent;
11139+ }
11140+
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;
11145+ } else if (rc) {
11146+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
11147+ "Timeout waiting for status message", 0);
11148+ sftp->rmdir_state = libssh2_NB_state_idle;
11149+ return -1;
11150+ }
11151+
11152+ sftp->rmdir_state = libssh2_NB_state_idle;
11153+
11154+ retcode = libssh2_ntohu32(data + 5);
11155+ LIBSSH2_FREE(session, data);
11156+
11157+ if (retcode == LIBSSH2_FX_OK) {
11158+ return 0;
11159+ } else {
11160+ sftp->last_errno = retcode;
11161+ libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
11162+ "SFTP Protocol Error", 0);
11163+ return -1;
11164+ }
11165+}
11166+
11167+/* }}} */
11168+
11169+/* {{{ libssh2_sftp_stat_ex
11170+ * Stat a file or symbolic link
11171+ */
11172+/* libssh2_sftp_stat_ex - NB-UNSAFE?? */
11173+LIBSSH2_API int
11174+libssh2_sftp_stat_ex(LIBSSH2_SFTP * sftp, const char *path,
11175+ unsigned int path_len, int stat_type,
11176+ LIBSSH2_SFTP_ATTRIBUTES * attrs)
11177+{
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 =
11183+ path_len + 13 +
11184+ ((stat_type ==
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 };
11189+ int rc;
11190+
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" :
11194+ (stat_type ==
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);
11200+ return -1;
11201+ }
11202+
11203+ libssh2_htonu32(s, packet_len - 4);
11204+ s += 4;
11205+ switch (stat_type) {
11206+ case LIBSSH2_SFTP_SETSTAT:
11207+ *(s++) = SSH_FXP_SETSTAT;
11208+ break;
11209+
11210+ case LIBSSH2_SFTP_LSTAT:
11211+ *(s++) = SSH_FXP_LSTAT;
11212+ break;
11213+
11214+ case LIBSSH2_SFTP_STAT:
11215+ default:
11216+ *(s++) = SSH_FXP_STAT;
11217+ }
11218+ sftp->stat_request_id = sftp->request_id++;
11219+ libssh2_htonu32(s, sftp->stat_request_id);
11220+ s += 4;
11221+ libssh2_htonu32(s, path_len);
11222+ s += 4;
11223+ memcpy(s, path, path_len);
11224+ s += path_len;
11225+ if (stat_type == LIBSSH2_SFTP_SETSTAT) {
11226+ s += libssh2_sftp_attr2bin(s, attrs);
11227+ }
11228+
11229+ sftp->stat_state = libssh2_NB_state_created;
11230+ }
11231+
11232+ if (sftp->stat_state == libssh2_NB_state_created) {
11233+ rc = libssh2_channel_write_ex(channel, 0, (char *) sftp->stat_packet,
11234+ packet_len);
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;
11243+ return -1;
11244+ }
11245+ LIBSSH2_FREE(session, sftp->stat_packet);
11246+ sftp->stat_packet = NULL;
11247+
11248+ sftp->stat_state = libssh2_NB_state_sent;
11249+ }
11250+
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;
11255+ } else if (rc) {
11256+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
11257+ "Timeout waiting for status message", 0);
11258+ sftp->stat_state = libssh2_NB_state_idle;
11259+ return -1;
11260+ }
11261+
11262+ sftp->stat_state = libssh2_NB_state_idle;
11263+
11264+ if (data[0] == SSH_FXP_STATUS) {
11265+ int retcode;
11266+
11267+ retcode = libssh2_ntohu32(data + 5);
11268+ LIBSSH2_FREE(session, data);
11269+ if (retcode == LIBSSH2_FX_OK) {
11270+ return 0;
11271+ } else {
11272+ sftp->last_errno = retcode;
11273+ libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
11274+ "SFTP Protocol Error", 0);
11275+ return -1;
11276+ }
11277+ }
11278+
11279+ memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
11280+ libssh2_sftp_bin2attr(attrs, data + 5);
11281+ LIBSSH2_FREE(session, data);
11282+
11283+ return 0;
11284+}
11285+
11286+/* }}} */
11287+
11288+/* {{{ libssh2_sftp_symlink_ex
11289+ * Read or set a symlink
11290+ */
11291+LIBSSH2_API int
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)
11295+{
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 =
11301+ path_len + 13 +
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 };
11306+ int rc;
11307+
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);
11311+ return -1;
11312+ }
11313+
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);
11320+ return -1;
11321+ }
11322+
11323+ _libssh2_debug(session, LIBSSH2_DBG_SFTP, "%s %s on %s",
11324+ (link_type ==
11325+ LIBSSH2_SFTP_SYMLINK) ? "Creating" : "Reading",
11326+ (link_type ==
11327+ LIBSSH2_SFTP_REALPATH) ? "realpath" : "symlink", path);
11328+
11329+ libssh2_htonu32(s, packet_len - 4);
11330+ s += 4;
11331+ switch (link_type) {
11332+ case LIBSSH2_SFTP_REALPATH:
11333+ *(s++) = SSH_FXP_REALPATH;
11334+ break;
11335+
11336+ case LIBSSH2_SFTP_SYMLINK:
11337+ *(s++) = SSH_FXP_SYMLINK;
11338+ break;
11339+
11340+ case LIBSSH2_SFTP_READLINK:
11341+ default:
11342+ *(s++) = SSH_FXP_READLINK;
11343+ }
11344+ sftp->symlink_request_id = sftp->request_id++;
11345+ libssh2_htonu32(s, sftp->symlink_request_id);
11346+ s += 4;
11347+ libssh2_htonu32(s, path_len);
11348+ s += 4;
11349+ memcpy(s, path, path_len);
11350+ s += path_len;
11351+ if (link_type == LIBSSH2_SFTP_SYMLINK) {
11352+ libssh2_htonu32(s, target_len);
11353+ s += 4;
11354+ memcpy(s, target, target_len);
11355+ s += target_len;
11356+ }
11357+
11358+ sftp->symlink_state = libssh2_NB_state_created;
11359+ }
11360+
11361+ if (sftp->symlink_state == libssh2_NB_state_created) {
11362+ rc = libssh2_channel_write_ex(channel, 0,
11363+ (char *) sftp->symlink_packet,
11364+ packet_len);
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;
11373+ return -1;
11374+ }
11375+ LIBSSH2_FREE(session, sftp->symlink_packet);
11376+ sftp->symlink_packet = NULL;
11377+
11378+ sftp->symlink_state = libssh2_NB_state_sent;
11379+ }
11380+
11381+ rc = sftp_packet_requirev(sftp, 2, link_responses,
11382+ sftp->symlink_request_id, &data,
11383+ &data_len);
11384+ if (rc == PACKET_EAGAIN) {
11385+ return PACKET_EAGAIN;
11386+ }
11387+ else if (rc) {
11388+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
11389+ "Timeout waiting for status message", 0);
11390+ sftp->symlink_state = libssh2_NB_state_idle;
11391+ return -1;
11392+ }
11393+
11394+ sftp->symlink_state = libssh2_NB_state_idle;
11395+
11396+ if (data[0] == SSH_FXP_STATUS) {
11397+ int retcode;
11398+
11399+ retcode = libssh2_ntohu32(data + 5);
11400+ LIBSSH2_FREE(session, data);
11401+ if (retcode == LIBSSH2_FX_OK) {
11402+ return 0;
11403+ } else {
11404+ sftp->last_errno = retcode;
11405+ libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
11406+ "SFTP Protocol Error", 0);
11407+ return -1;
11408+ }
11409+ }
11410+
11411+ if (libssh2_ntohu32(data + 5) < 1) {
11412+ libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
11413+ "Invalid READLINK/REALPATH response, no name entries",
11414+ 0);
11415+ LIBSSH2_FREE(session, data);
11416+ return -1;
11417+ }
11418+
11419+ link_len = libssh2_ntohu32(data + 9);
11420+ if (link_len >= target_len) {
11421+ link_len = target_len - 1;
11422+ }
11423+ memcpy(target, data + 13, link_len);
11424+ target[link_len] = 0;
11425+ LIBSSH2_FREE(session, data);
11426+
11427+ return link_len;
11428+}
11429+
11430+/* }}} */
11431+
11432+/* {{{ libssh2_sftp_last_error
11433+ * Returns the last error code reported by SFTP
11434+ */
11435+LIBSSH2_API unsigned long
11436+libssh2_sftp_last_error(LIBSSH2_SFTP * sftp)
11437+{
11438+ return sftp->last_errno;
11439+}
11440+
11441+/* }}} */
11442
11443Property changes on: libssh2/src/sftp.c
11444___________________________________________________________________
11445Added: svn:mime-type
11446 + text/x-c
11447Added: svn:keywords
11448 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
11449Added: cvs2svn:cvs-rev
11450 + 1.2
11451Added: svn:eol-style
11452 + native
11453
11454Index: 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)
11458@@ -0,0 +1,44 @@
11459+#ifndef LIBSSH2_CONFIG_H
11460+#define LIBSSH2_CONFIG_H
11461+
11462+#ifndef WIN32
11463+#define WIN32
11464+#endif
11465+#include <winsock2.h>
11466+#include <mswsock.h>
11467+#include <ws2tcpip.h>
11468+
11469+#ifdef __MINGW32__
11470+#define HAVE_UNISTD_H
11471+#define HAVE_INTTYPES_H
11472+#define HAVE_SYS_TIME_H
11473+#endif
11474+
11475+#define HAVE_WINSOCK2_H
11476+#define HAVE_IOCTLSOCKET
11477+#define HAVE_SELECT
11478+
11479+#ifdef _MSC_VER
11480+#define snprintf _snprintf
11481+#if _MSC_VER < 1500
11482+#define vsnprintf _vsnprintf
11483+#else
11484+#define ssize_t SSIZE_T
11485+#define uint32_t UINT32
11486+#endif
11487+#define strncasecmp _strnicmp
11488+#define strcasecmp _stricmp
11489+#else
11490+#define strncasecmp strnicmp
11491+#define strcasecmp stricmp
11492+#endif /* _MSC_VER */
11493+
11494+/* Compile in zlib support */
11495+#define LIBSSH2_HAVE_ZLIB 1
11496+
11497+/* Enable newer diffie-hellman-group-exchange-sha1 syntax */
11498+#define LIBSSH2_DH_GEX_NEW 1
11499+
11500+#endif /* LIBSSH2_CONFIG_H */
11501+
11502+
11503
11504Property changes on: libssh2/src/libssh2_config.h.in.w32
11505___________________________________________________________________
11506Added: svn:keywords
11507 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
11508Added: cvs2svn:cvs-rev
11509 + 1.1
11510Added: svn:eol-style
11511 + native
11512Added: svn:executable
11513 + *
11514
11515Index: libssh2/src/pem.c
11516===================================================================
11517--- libssh2/src/pem.c (.../tags/RELEASE_0_11_0)
11518+++ libssh2/src/pem.c (.../trunk)
11519@@ -0,0 +1,209 @@
11520+/* Copyright (C) 2007 The Written Word, Inc.
11521+ * Copyright (C) 2008, Simon Josefsson
11522+ * All rights reserved.
11523+ *
11524+ * Redistribution and use in source and binary forms,
11525+ * with or without modification, are permitted provided
11526+ * that the following conditions are met:
11527+ *
11528+ * Redistributions of source code must retain the above
11529+ * copyright notice, this list of conditions and the
11530+ * following disclaimer.
11531+ *
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.
11536+ *
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.
11541+ *
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.
11556+ */
11557+
11558+#include "libssh2_priv.h"
11559+
11560+static int
11561+readline(char *line, int line_size, FILE * fp)
11562+{
11563+ if (!fgets(line, line_size, fp)) {
11564+ return -1;
11565+ }
11566+ if (*line && line[strlen(line) - 1] == '\n') {
11567+ line[strlen(line) - 1] = '\0';
11568+ }
11569+ if (*line && line[strlen(line) - 1] == '\r') {
11570+ line[strlen(line) - 1] = '\0';
11571+ }
11572+ return 0;
11573+}
11574+
11575+#define LINE_SIZE 128
11576+
11577+int
11578+_libssh2_pem_parse(LIBSSH2_SESSION * session,
11579+ const char *headerbegin,
11580+ const char *headerend,
11581+ FILE * fp, unsigned char **data, unsigned int *datalen)
11582+{
11583+ char line[LINE_SIZE];
11584+ char *b64data = NULL;
11585+ unsigned int b64datalen = 0;
11586+ int ret;
11587+
11588+ do {
11589+ if (readline(line, LINE_SIZE, fp)) {
11590+ return -1;
11591+ }
11592+ }
11593+ while (strcmp(line, headerbegin) != 0);
11594+
11595+ *line = '\0';
11596+
11597+ do {
11598+ if (*line) {
11599+ char *tmp;
11600+ size_t linelen;
11601+
11602+ linelen = strlen(line);
11603+ tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen);
11604+ if (!tmp) {
11605+ ret = -1;
11606+ goto out;
11607+ }
11608+ memcpy(tmp + b64datalen, line, linelen);
11609+ b64data = tmp;
11610+ b64datalen += linelen;
11611+ }
11612+
11613+ if (readline(line, LINE_SIZE, fp)) {
11614+ ret = -1;
11615+ goto out;
11616+ }
11617+ } while (strcmp(line, headerend) != 0);
11618+
11619+ if (libssh2_base64_decode(session, (char**) data, datalen,
11620+ b64data, b64datalen)) {
11621+ ret = -1;
11622+ goto out;
11623+ }
11624+
11625+ ret = 0;
11626+ out:
11627+ if (b64data) {
11628+ LIBSSH2_FREE(session, b64data);
11629+ }
11630+ return ret;
11631+}
11632+
11633+static int
11634+read_asn1_length(const unsigned char *data,
11635+ unsigned int datalen, unsigned int *len)
11636+{
11637+ unsigned int lenlen;
11638+ int nextpos;
11639+
11640+ if (datalen < 1) {
11641+ return -1;
11642+ }
11643+ *len = data[0];
11644+
11645+ if (*len >= 0x80) {
11646+ lenlen = *len & 0x7F;
11647+ *len = data[1];
11648+ if (1 + lenlen > datalen) {
11649+ return -1;
11650+ }
11651+ if (lenlen > 1) {
11652+ *len <<= 8;
11653+ *len |= data[2];
11654+ }
11655+ } else {
11656+ lenlen = 0;
11657+ }
11658+
11659+ nextpos = 1 + lenlen;
11660+ if (lenlen > 2 || 1 + lenlen + *len > datalen) {
11661+ return -1;
11662+ }
11663+
11664+ return nextpos;
11665+}
11666+
11667+int
11668+_libssh2_pem_decode_sequence(unsigned char **data, unsigned int *datalen)
11669+{
11670+ unsigned int len;
11671+ int lenlen;
11672+
11673+ if (*datalen < 1) {
11674+ return -1;
11675+ }
11676+
11677+ if ((*data)[0] != '\x30') {
11678+ return -1;
11679+ }
11680+
11681+ (*data)++;
11682+ (*datalen)--;
11683+
11684+ lenlen = read_asn1_length(*data, *datalen, &len);
11685+ if (lenlen < 0 || lenlen + len != *datalen) {
11686+ return -1;
11687+ }
11688+
11689+ *data += lenlen;
11690+ *datalen -= lenlen;
11691+
11692+ return 0;
11693+}
11694+
11695+int
11696+_libssh2_pem_decode_integer(unsigned char **data, unsigned int *datalen,
11697+ unsigned char **i, unsigned int *ilen)
11698+{
11699+ unsigned int len;
11700+ int lenlen;
11701+
11702+ if (*datalen < 1) {
11703+ return -1;
11704+ }
11705+
11706+ if ((*data)[0] != '\x02') {
11707+ return -1;
11708+ }
11709+
11710+ (*data)++;
11711+ (*datalen)--;
11712+
11713+ lenlen = read_asn1_length(*data, *datalen, &len);
11714+ if (lenlen < 0 || lenlen + len > *datalen) {
11715+ return -1;
11716+ }
11717+
11718+ *data += lenlen;
11719+ *datalen -= lenlen;
11720+
11721+ *i = *data;
11722+ *ilen = len;
11723+
11724+ *data += len;
11725+ *datalen -= len;
11726+
11727+ return 0;
11728+}
11729
11730Property changes on: libssh2/src/pem.c
11731___________________________________________________________________
11732Added: svn:mime-type
11733 + text/x-c
11734Added: svn:keywords
11735 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
11736Added: cvs2svn:cvs-rev
11737 + 1.1
11738Added: svn:eol-style
11739 + native
11740Added: svn:executable
11741 + *
11742
11743Index: libssh2/src/session.c
11744===================================================================
11745--- libssh2/src/session.c (.../tags/RELEASE_0_11_0)
11746+++ libssh2/src/session.c (.../trunk)
11747@@ -0,0 +1,1554 @@
11748+/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
11749+ * All rights reserved.
11750+ *
11751+ * Redistribution and use in source and binary forms,
11752+ * with or without modification, are permitted provided
11753+ * that the following conditions are met:
11754+ *
11755+ * Redistributions of source code must retain the above
11756+ * copyright notice, this list of conditions and the
11757+ * following disclaimer.
11758+ *
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.
11763+ *
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.
11768+ *
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.
11783+ */
11784+
11785+#include "libssh2_priv.h"
11786+#include <errno.h>
11787+#ifdef HAVE_UNISTD_H
11788+#include <unistd.h>
11789+#endif
11790+#include <stdlib.h>
11791+#include <fcntl.h>
11792+
11793+#ifdef HAVE_GETTIMEOFDAY
11794+#include <sys/time.h>
11795+#endif
11796+#ifdef HAVE_ALLOCA_H
11797+#include <alloca.h>
11798+#endif
11799+
11800+/* {{{ libssh2_default_alloc
11801+ */
11802+static
11803+LIBSSH2_ALLOC_FUNC(libssh2_default_alloc)
11804+{
11805+ (void) abstract;
11806+ return malloc(count);
11807+}
11808+
11809+/* }}} */
11810+
11811+/* {{{ libssh2_default_free
11812+ */
11813+static
11814+LIBSSH2_FREE_FUNC(libssh2_default_free)
11815+{
11816+ (void) abstract;
11817+ free(ptr);
11818+}
11819+
11820+/* }}} */
11821+
11822+/* {{{ libssh2_default_realloc
11823+ */
11824+static
11825+LIBSSH2_REALLOC_FUNC(libssh2_default_realloc)
11826+{
11827+ (void) abstract;
11828+ return realloc(ptr, count);
11829+}
11830+
11831+/* }}} */
11832+
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
11837+ */
11838+static int
11839+libssh2_banner_receive(LIBSSH2_SESSION * session)
11840+{
11841+ int ret;
11842+ int banner_len;
11843+
11844+ if (session->banner_TxRx_state == libssh2_NB_state_idle) {
11845+ banner_len = 0;
11846+
11847+ session->banner_TxRx_state = libssh2_NB_state_created;
11848+ } else {
11849+ banner_len = session->banner_TxRx_total_send;
11850+ }
11851+
11852+ while ((banner_len < (int) sizeof(session->banner_TxRx_banner)) &&
11853+ ((banner_len == 0)
11854+ || (session->banner_TxRx_banner[banner_len - 1] != '\n'))) {
11855+ char c = '\0';
11856+
11857+ ret =
11858+ recv(session->socket_fd, &c, 1,
11859+ LIBSSH2_SOCKET_RECV_FLAGS(session));
11860+
11861+ if (ret < 0) {
11862+#ifdef WIN32
11863+ switch (WSAGetLastError()) {
11864+ case WSAEWOULDBLOCK:
11865+ errno = EAGAIN;
11866+ break;
11867+
11868+ case WSAENOTSOCK:
11869+ errno = EBADF;
11870+ break;
11871+
11872+ case WSAENOTCONN:
11873+ case WSAECONNABORTED:
11874+ errno = WSAENOTCONN;
11875+ break;
11876+
11877+ case WSAEINTR:
11878+ errno = EINTR;
11879+ break;
11880+ }
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;
11887+ }
11888+
11889+ /* Some kinda error */
11890+ session->banner_TxRx_state = libssh2_NB_state_idle;
11891+ session->banner_TxRx_total_send = 0;
11892+ return 1;
11893+ }
11894+
11895+ if (ret == 0) {
11896+ session->socket_state = LIBSSH2_SOCKET_DISCONNECTED;
11897+ return PACKET_FAIL;
11898+ }
11899+
11900+ if (c == '\0') {
11901+ /* NULLs are not allowed in SSH banners */
11902+ session->banner_TxRx_state = libssh2_NB_state_idle;
11903+ session->banner_TxRx_total_send = 0;
11904+ return 1;
11905+ }
11906+
11907+ session->banner_TxRx_banner[banner_len++] = c;
11908+ }
11909+
11910+ while (banner_len &&
11911+ ((session->banner_TxRx_banner[banner_len - 1] == '\n') ||
11912+ (session->banner_TxRx_banner[banner_len - 1] == '\r'))) {
11913+ banner_len--;
11914+ }
11915+
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;
11919+
11920+ if (!banner_len)
11921+ return 1;
11922+
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);
11927+ return 1;
11928+ }
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);
11933+ return 0;
11934+}
11935+
11936+/* }}} */
11937+
11938+/* {{{ libssh2_banner_send
11939+ * Send the default banner, or the one set via libssh2_setopt_string
11940+ *
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.
11945+ */
11946+static int
11947+libssh2_banner_send(LIBSSH2_SESSION * session)
11948+{
11949+ char *banner = (char *) LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF;
11950+ int banner_len = sizeof(LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF) - 1;
11951+ ssize_t ret;
11952+#ifdef LIBSSH2DEBUG
11953+ char banner_dup[256];
11954+#endif
11955+
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;
11961+ }
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';
11967+ } else {
11968+ memcpy(banner_dup, banner, 255);
11969+ banner[255] = '\0';
11970+ }
11971+
11972+ _libssh2_debug(session, LIBSSH2_DBG_TRANS, "Sending Banner: %s",
11973+ banner_dup);
11974+#endif
11975+
11976+ session->banner_TxRx_state = libssh2_NB_state_created;
11977+ }
11978+
11979+ ret =
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));
11983+
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;
11991+ }
11992+ session->banner_TxRx_state = libssh2_NB_state_idle;
11993+ session->banner_TxRx_total_send = 0;
11994+ return PACKET_FAIL;
11995+ }
11996+
11997+ /* Set the state back to idle */
11998+ session->banner_TxRx_state = libssh2_NB_state_idle;
11999+ session->banner_TxRx_total_send = 0;
12000+
12001+ return 0;
12002+}
12003+
12004+/* }}} */
12005+
12006+/*
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.
12010+ */
12011+static int
12012+_libssh2_nonblock(int sockfd, /* operate on this */
12013+ int nonblock /* TRUE or FALSE */ )
12014+{
12015+#undef SETBLOCK
12016+#define SETBLOCK 0
12017+#ifdef HAVE_O_NONBLOCK
12018+ /* most recent unix versions */
12019+ int flags;
12020+
12021+ flags = fcntl(sockfd, F_GETFL, 0);
12022+ if (nonblock)
12023+ return fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
12024+ else
12025+ return fcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK));
12026+#undef SETBLOCK
12027+#define SETBLOCK 1
12028+#endif
12029+
12030+#if defined(HAVE_FIONBIO) && (SETBLOCK == 0)
12031+ /* older unix versions */
12032+ int flags;
12033+
12034+ flags = nonblock;
12035+ return ioctl(sockfd, FIONBIO, &flags);
12036+#undef SETBLOCK
12037+#define SETBLOCK 2
12038+#endif
12039+
12040+#if defined(HAVE_IOCTLSOCKET) && (SETBLOCK == 0)
12041+ /* Windows? */
12042+ unsigned long flags;
12043+ flags = nonblock;
12044+
12045+ return ioctlsocket(sockfd, FIONBIO, &flags);
12046+#undef SETBLOCK
12047+#define SETBLOCK 3
12048+#endif
12049+
12050+#if defined(HAVE_IOCTLSOCKET_CASE) && (SETBLOCK == 0)
12051+ /* presumably for Amiga */
12052+ return IoctlSocket(sockfd, FIONBIO, (long) nonblock);
12053+#undef SETBLOCK
12054+#define SETBLOCK 4
12055+#endif
12056+
12057+#if defined(HAVE_SO_NONBLOCK) && (SETBLOCK == 0)
12058+ /* BeOS */
12059+ long b = nonblock ? 1 : 0;
12060+ return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b));
12061+#undef SETBLOCK
12062+#define SETBLOCK 5
12063+#endif
12064+
12065+#ifdef HAVE_DISABLED_NONBLOCKING
12066+ return 0; /* returns success */
12067+#undef SETBLOCK
12068+#define SETBLOCK 6
12069+#endif
12070+
12071+#if (SETBLOCK == 0)
12072+#error "no non-blocking method was found/used/set"
12073+#endif
12074+}
12075+
12076+/*
12077+ * _libssh2_get_socket_nonblocking() gets the given blocking or non-blocking
12078+ * state of the socket.
12079+ */
12080+static int
12081+_libssh2_get_socket_nonblocking(int sockfd)
12082+{ /* operate on this */
12083+#undef GETBLOCK
12084+#define GETBLOCK 0
12085+#ifdef HAVE_O_NONBLOCK
12086+ /* most recent unix versions */
12087+ int flags;
12088+
12089+ if ((flags = fcntl(sockfd, F_GETFL, 0)) == -1) {
12090+ /* Assume blocking on error */
12091+ return 1;
12092+ }
12093+ return (flags & O_NONBLOCK);
12094+#undef GETBLOCK
12095+#define GETBLOCK 1
12096+#endif
12097+
12098+#if defined(WSAEWOULDBLOCK) && (GETBLOCK == 0)
12099+ /* Windows? */
12100+ unsigned int option_value;
12101+ socklen_t option_len = sizeof(option_value);
12102+
12103+ if (getsockopt
12104+ (sockfd, SOL_SOCKET, SO_ERROR, (void *) &option_value, &option_len)) {
12105+ /* Assume blocking on error */
12106+ return 1;
12107+ }
12108+ return (int) option_value;
12109+#undef GETBLOCK
12110+#define GETBLOCK 2
12111+#endif
12112+
12113+#if defined(HAVE_SO_NONBLOCK) && (GETBLOCK == 0)
12114+ /* BeOS */
12115+ long b;
12116+ if (getsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b))) {
12117+ /* Assume blocking on error */
12118+ return 1;
12119+ }
12120+ return (int) b;
12121+#undef GETBLOCK
12122+#define GETBLOCK 5
12123+#endif
12124+
12125+#ifdef HAVE_DISABLED_NONBLOCKING
12126+ return 1; /* returns blocking */
12127+#undef GETBLOCK
12128+#define GETBLOCK 6
12129+#endif
12130+
12131+#if (GETBLOCK == 0)
12132+#error "no non-blocking method was found/used/get"
12133+#endif
12134+}
12135+
12136+/* {{{ libssh2_banner_set
12137+ * Set the local banner
12138+ */
12139+LIBSSH2_API int
12140+libssh2_banner_set(LIBSSH2_SESSION * session, const char *banner)
12141+{
12142+ int banner_len = banner ? strlen(banner) : 0;
12143+
12144+ if (session->local.banner) {
12145+ LIBSSH2_FREE(session, session->local.banner);
12146+ session->local.banner = NULL;
12147+ }
12148+
12149+ if (!banner_len) {
12150+ return 0;
12151+ }
12152+
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);
12157+ return -1;
12158+ }
12159+
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';
12167+
12168+ return 0;
12169+}
12170+
12171+/* }}} */
12172+
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)
12178+ */
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)
12183+{
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;
12188+
12189+ if (my_alloc) {
12190+ local_alloc = my_alloc;
12191+ }
12192+ if (my_free) {
12193+ local_free = my_free;
12194+ }
12195+ if (my_realloc) {
12196+ local_realloc = my_realloc;
12197+ }
12198+
12199+ session = local_alloc(sizeof(LIBSSH2_SESSION), abstract);
12200+ if (session) {
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();
12209+ }
12210+ return session;
12211+}
12212+
12213+/* }}} */
12214+
12215+/* {{{ libssh2_session_callback_set
12216+ * Set (or reset) a callback function
12217+ * Returns the prior address
12218+ *
12219+ * FIXME: this function relies on that we can typecast function pointers
12220+ * to void pointers, which isn't allowed in ISO C!
12221+ */
12222+LIBSSH2_API void *
12223+libssh2_session_callback_set(LIBSSH2_SESSION * session,
12224+ int cbtype, void *callback)
12225+{
12226+ void *oldcb;
12227+
12228+ switch (cbtype) {
12229+ case LIBSSH2_CALLBACK_IGNORE:
12230+ oldcb = session->ssh_msg_ignore;
12231+ session->ssh_msg_ignore = callback;
12232+ return oldcb;
12233+
12234+ case LIBSSH2_CALLBACK_DEBUG:
12235+ oldcb = session->ssh_msg_debug;
12236+ session->ssh_msg_debug = callback;
12237+ return oldcb;
12238+
12239+ case LIBSSH2_CALLBACK_DISCONNECT:
12240+ oldcb = session->ssh_msg_disconnect;
12241+ session->ssh_msg_disconnect = callback;
12242+ return oldcb;
12243+
12244+ case LIBSSH2_CALLBACK_MACERROR:
12245+ oldcb = session->macerror;
12246+ session->macerror = callback;
12247+ return oldcb;
12248+
12249+ case LIBSSH2_CALLBACK_X11:
12250+ oldcb = session->x11;
12251+ session->x11 = callback;
12252+ return oldcb;
12253+
12254+ }
12255+ _libssh2_debug(session, LIBSSH2_DBG_TRANS, "Setting Callback %d", cbtype);
12256+
12257+ return NULL;
12258+}
12259+
12260+/* }}} */
12261+
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.
12268+ */
12269+LIBSSH2_API int
12270+libssh2_session_startup(LIBSSH2_SESSION * session, int sock)
12271+{
12272+ int rc;
12273+
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 */
12278+ if (sock < 0) {
12279+ /* Did we forget something? */
12280+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_NONE,
12281+ "Bad socket provided", 0);
12282+ return LIBSSH2_ERROR_SOCKET_NONE;
12283+ }
12284+ session->socket_fd = sock;
12285+
12286+ session->socket_block =
12287+ !_libssh2_get_socket_nonblocking(session->socket_fd);
12288+ if (session->socket_block) {
12289+ /*
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
12292+ * be sure
12293+ */
12294+ _libssh2_nonblock(session->socket_fd, 0);
12295+ }
12296+
12297+ session->startup_state = libssh2_NB_state_created;
12298+ }
12299+
12300+ /* TODO: Liveness check */
12301+
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;
12308+ } else if (rc) {
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;
12313+ }
12314+
12315+ session->startup_state = libssh2_NB_state_sent;
12316+ }
12317+
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;
12324+ } else if (rc) {
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;
12329+ }
12330+
12331+ session->startup_state = libssh2_NB_state_sent1;
12332+ }
12333+
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;
12340+ } else if (rc) {
12341+ libssh2_error(session, LIBSSH2_ERROR_KEX_FAILURE,
12342+ "Unable to exchange encryption keys", 0);
12343+ return LIBSSH2_ERROR_KEX_FAILURE;
12344+ }
12345+
12346+ session->startup_state = libssh2_NB_state_sent2;
12347+ }
12348+
12349+ if (session->startup_state == libssh2_NB_state_sent2) {
12350+ _libssh2_debug(session, LIBSSH2_DBG_TRANS,
12351+ "Requesting userauth service");
12352+
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);
12359+
12360+ session->startup_state = libssh2_NB_state_sent3;
12361+ }
12362+
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;
12370+ } else if (rc) {
12371+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
12372+ "Unable to ask for ssh-userauth service", 0);
12373+ return LIBSSH2_ERROR_SOCKET_SEND;
12374+ }
12375+
12376+ session->startup_state = libssh2_NB_state_sent4;
12377+ }
12378+
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;
12386+ } else if (rc) {
12387+ return LIBSSH2_ERROR_SOCKET_DISCONNECT;
12388+ }
12389+ session->startup_service_length =
12390+ libssh2_ntohu32(session->startup_data + 1);
12391+
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;
12400+ }
12401+ LIBSSH2_FREE(session, session->startup_data);
12402+ session->startup_data = NULL;
12403+
12404+ session->startup_state = libssh2_NB_state_idle;
12405+
12406+ return 0;
12407+ }
12408+
12409+ /* just for safety return some error */
12410+ return LIBSSH2_ERROR_INVAL;
12411+}
12412+
12413+/* }}} */
12414+
12415+/* {{{ proto libssh2_session_free
12416+ * Frees the memory allocated to the session
12417+ * Also closes and frees any channels attached to this session
12418+ */
12419+LIBSSH2_API int
12420+libssh2_session_free(LIBSSH2_SESSION * session)
12421+{
12422+ int rc;
12423+
12424+ if (session->free_state == libssh2_NB_state_idle) {
12425+ _libssh2_debug(session, LIBSSH2_DBG_TRANS, "Freeing session resource",
12426+ session->remote.banner);
12427+
12428+ session->state = libssh2_NB_state_created;
12429+ }
12430+
12431+ if (session->free_state == libssh2_NB_state_created) {
12432+ while (session->channels.head) {
12433+ LIBSSH2_CHANNEL *tmp = session->channels.head;
12434+
12435+ rc = libssh2_channel_free(session->channels.head);
12436+ if (rc == PACKET_EAGAIN) {
12437+ return PACKET_EAGAIN;
12438+ }
12439+ if (tmp == session->channels.head) {
12440+ /* channel_free couldn't do it's job, perform a messy cleanup */
12441+ tmp = session->channels.head;
12442+
12443+ /* unlink */
12444+ session->channels.head = tmp->next;
12445+
12446+ /* free */
12447+ LIBSSH2_FREE(session, tmp);
12448+
12449+ /* reverse linking isn't important here, we're killing the structure */
12450+ }
12451+ }
12452+
12453+ session->state = libssh2_NB_state_sent;
12454+ }
12455+
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;
12461+ }
12462+ }
12463+
12464+ session->state = libssh2_NB_state_sent1;
12465+ }
12466+
12467+ if (session->state & LIBSSH2_STATE_NEWKEYS) {
12468+ /* hostkey */
12469+ if (session->hostkey && session->hostkey->dtor) {
12470+ session->hostkey->dtor(session, &session->server_hostkey_abstract);
12471+ }
12472+
12473+ /* Client to Server */
12474+ /* crypt */
12475+ if (session->local.crypt && session->local.crypt->dtor) {
12476+ session->local.crypt->dtor(session,
12477+ &session->local.crypt_abstract);
12478+ }
12479+ /* comp */
12480+ if (session->local.comp && session->local.comp->dtor) {
12481+ session->local.comp->dtor(session, 1,
12482+ &session->local.comp_abstract);
12483+ }
12484+ /* mac */
12485+ if (session->local.mac && session->local.mac->dtor) {
12486+ session->local.mac->dtor(session, &session->local.mac_abstract);
12487+ }
12488+
12489+ /* Server to Client */
12490+ /* crypt */
12491+ if (session->remote.crypt && session->remote.crypt->dtor) {
12492+ session->remote.crypt->dtor(session,
12493+ &session->remote.crypt_abstract);
12494+ }
12495+ /* comp */
12496+ if (session->remote.comp && session->remote.comp->dtor) {
12497+ session->remote.comp->dtor(session, 0,
12498+ &session->remote.comp_abstract);
12499+ }
12500+ /* mac */
12501+ if (session->remote.mac && session->remote.mac->dtor) {
12502+ session->remote.mac->dtor(session, &session->remote.mac_abstract);
12503+ }
12504+
12505+ /* session_id */
12506+ if (session->session_id) {
12507+ LIBSSH2_FREE(session, session->session_id);
12508+ }
12509+ }
12510+
12511+ /* Free banner(s) */
12512+ if (session->remote.banner) {
12513+ LIBSSH2_FREE(session, session->remote.banner);
12514+ }
12515+ if (session->local.banner) {
12516+ LIBSSH2_FREE(session, session->local.banner);
12517+ }
12518+
12519+ /* Free preference(s) */
12520+ if (session->kex_prefs) {
12521+ LIBSSH2_FREE(session, session->kex_prefs);
12522+ }
12523+ if (session->hostkey_prefs) {
12524+ LIBSSH2_FREE(session, session->hostkey_prefs);
12525+ }
12526+
12527+ if (session->local.crypt_prefs) {
12528+ LIBSSH2_FREE(session, session->local.crypt_prefs);
12529+ }
12530+ if (session->local.mac_prefs) {
12531+ LIBSSH2_FREE(session, session->local.mac_prefs);
12532+ }
12533+ if (session->local.comp_prefs) {
12534+ LIBSSH2_FREE(session, session->local.comp_prefs);
12535+ }
12536+ if (session->local.lang_prefs) {
12537+ LIBSSH2_FREE(session, session->local.lang_prefs);
12538+ }
12539+
12540+ if (session->remote.crypt_prefs) {
12541+ LIBSSH2_FREE(session, session->remote.crypt_prefs);
12542+ }
12543+ if (session->remote.mac_prefs) {
12544+ LIBSSH2_FREE(session, session->remote.mac_prefs);
12545+ }
12546+ if (session->remote.comp_prefs) {
12547+ LIBSSH2_FREE(session, session->remote.comp_prefs);
12548+ }
12549+ if (session->remote.lang_prefs) {
12550+ LIBSSH2_FREE(session, session->remote.lang_prefs);
12551+ }
12552+
12553+ /*
12554+ * Make sure all memory used in the state variables are free
12555+ */
12556+ if (session->startup_data) {
12557+ LIBSSH2_FREE(session, session->startup_data);
12558+ }
12559+ if (session->disconnect_data) {
12560+ LIBSSH2_FREE(session, session->disconnect_data);
12561+ }
12562+ if (session->userauth_list_data) {
12563+ LIBSSH2_FREE(session, session->userauth_list_data);
12564+ }
12565+ if (session->userauth_pswd_data) {
12566+ LIBSSH2_FREE(session, session->userauth_pswd_data);
12567+ }
12568+ if (session->userauth_pswd_newpw) {
12569+ LIBSSH2_FREE(session, session->userauth_pswd_newpw);
12570+ }
12571+ if (session->userauth_host_packet) {
12572+ LIBSSH2_FREE(session, session->userauth_host_packet);
12573+ }
12574+ if (session->userauth_host_method) {
12575+ LIBSSH2_FREE(session, session->userauth_host_method);
12576+ }
12577+ if (session->userauth_host_data) {
12578+ LIBSSH2_FREE(session, session->userauth_host_data);
12579+ }
12580+ if (session->userauth_pblc_data) {
12581+ LIBSSH2_FREE(session, session->userauth_pblc_data);
12582+ }
12583+ if (session->userauth_pblc_packet) {
12584+ LIBSSH2_FREE(session, session->userauth_pblc_packet);
12585+ }
12586+ if (session->userauth_pblc_method) {
12587+ LIBSSH2_FREE(session, session->userauth_pblc_method);
12588+ }
12589+ if (session->userauth_kybd_data) {
12590+ LIBSSH2_FREE(session, session->userauth_kybd_data);
12591+ }
12592+ if (session->userauth_kybd_packet) {
12593+ LIBSSH2_FREE(session, session->userauth_kybd_packet);
12594+ }
12595+ if (session->userauth_kybd_auth_instruction) {
12596+ LIBSSH2_FREE(session, session->userauth_kybd_auth_instruction);
12597+ }
12598+ if (session->open_packet) {
12599+ LIBSSH2_FREE(session, session->open_packet);
12600+ }
12601+ if (session->open_data) {
12602+ LIBSSH2_FREE(session, session->open_data);
12603+ }
12604+ if (session->direct_message) {
12605+ LIBSSH2_FREE(session, session->direct_message);
12606+ }
12607+ if (session->fwdLstn_packet) {
12608+ LIBSSH2_FREE(session, session->fwdLstn_packet);
12609+ }
12610+ if (session->pkeyInit_data) {
12611+ LIBSSH2_FREE(session, session->pkeyInit_data);
12612+ }
12613+ if (session->scpRecv_command) {
12614+ LIBSSH2_FREE(session, session->scpRecv_command);
12615+ }
12616+ if (session->scpSend_command) {
12617+ LIBSSH2_FREE(session, session->scpSend_command);
12618+ }
12619+ if (session->scpRecv_err_msg) {
12620+ LIBSSH2_FREE(session, session->scpRecv_err_msg);
12621+ }
12622+ if (session->scpSend_err_msg) {
12623+ LIBSSH2_FREE(session, session->scpSend_err_msg);
12624+ }
12625+
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);
12629+ }
12630+
12631+ /* Cleanup any remaining packets */
12632+ while (session->packets.head) {
12633+ LIBSSH2_PACKET *tmp = session->packets.head;
12634+
12635+ /* unlink */
12636+ session->packets.head = tmp->next;
12637+
12638+ /* free */
12639+ LIBSSH2_FREE(session, tmp->data);
12640+ LIBSSH2_FREE(session, tmp);
12641+ }
12642+
12643+ LIBSSH2_FREE(session, session);
12644+
12645+ return 0;
12646+}
12647+
12648+/* }}} */
12649+
12650+/* {{{ libssh2_session_disconnect_ex
12651+ */
12652+LIBSSH2_API int
12653+libssh2_session_disconnect_ex(LIBSSH2_SESSION * session, int reason,
12654+ const char *description, const char *lang)
12655+{
12656+ unsigned char *s;
12657+ unsigned long descr_len = 0, lang_len = 0;
12658+ int rc;
12659+
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);
12666+ }
12667+ if (lang) {
12668+ lang_len = strlen(lang);
12669+ }
12670+ /* 13 = packet_type(1) + reason code(4) + descr_len(4) + lang_len(4) */
12671+ session->disconnect_data_len = descr_len + lang_len + 13;
12672+
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",
12678+ 0);
12679+ session->disconnect_state = libssh2_NB_state_idle;
12680+ return -1;
12681+ }
12682+
12683+ *(s++) = SSH_MSG_DISCONNECT;
12684+ libssh2_htonu32(s, reason);
12685+ s += 4;
12686+
12687+ libssh2_htonu32(s, descr_len);
12688+ s += 4;
12689+ if (description) {
12690+ memcpy(s, description, descr_len);
12691+ s += descr_len;
12692+ }
12693+
12694+ libssh2_htonu32(s, lang_len);
12695+ s += 4;
12696+ if (lang) {
12697+ memcpy(s, lang, lang_len);
12698+ s += lang_len;
12699+ }
12700+
12701+ session->disconnect_state = libssh2_NB_state_created;
12702+ }
12703+
12704+ rc = libssh2_packet_write(session, session->disconnect_data,
12705+ session->disconnect_data_len);
12706+ if (rc == PACKET_EAGAIN) {
12707+ return PACKET_EAGAIN;
12708+ }
12709+
12710+ LIBSSH2_FREE(session, session->disconnect_data);
12711+ session->disconnect_data = NULL;
12712+ session->disconnect_state = libssh2_NB_state_idle;
12713+
12714+ return 0;
12715+}
12716+
12717+/* }}} */
12718+
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
12723+ */
12724+LIBSSH2_API const char *
12725+libssh2_session_methods(LIBSSH2_SESSION * session, int method_type)
12726+{
12727+ /* All methods have char *name as their first element */
12728+ const LIBSSH2_KEX_METHOD *method = NULL;
12729+
12730+ switch (method_type) {
12731+ case LIBSSH2_METHOD_KEX:
12732+ method = session->kex;
12733+ break;
12734+
12735+ case LIBSSH2_METHOD_HOSTKEY:
12736+ method = (LIBSSH2_KEX_METHOD *) session->hostkey;
12737+ break;
12738+
12739+ case LIBSSH2_METHOD_CRYPT_CS:
12740+ method = (LIBSSH2_KEX_METHOD *) session->local.crypt;
12741+ break;
12742+
12743+ case LIBSSH2_METHOD_CRYPT_SC:
12744+ method = (LIBSSH2_KEX_METHOD *) session->remote.crypt;
12745+ break;
12746+
12747+ case LIBSSH2_METHOD_MAC_CS:
12748+ method = (LIBSSH2_KEX_METHOD *) session->local.mac;
12749+ break;
12750+
12751+ case LIBSSH2_METHOD_MAC_SC:
12752+ method = (LIBSSH2_KEX_METHOD *) session->remote.mac;
12753+ break;
12754+
12755+ case LIBSSH2_METHOD_COMP_CS:
12756+ method = (LIBSSH2_KEX_METHOD *) session->local.comp;
12757+ break;
12758+
12759+ case LIBSSH2_METHOD_COMP_SC:
12760+ method = (LIBSSH2_KEX_METHOD *) session->remote.comp;
12761+ break;
12762+
12763+ case LIBSSH2_METHOD_LANG_CS:
12764+ return "";
12765+ break;
12766+
12767+ case LIBSSH2_METHOD_LANG_SC:
12768+ return "";
12769+ break;
12770+
12771+ default:
12772+ libssh2_error(session, LIBSSH2_ERROR_INVAL,
12773+ "Invalid parameter specified for method_type", 0);
12774+ return NULL;
12775+ break;
12776+ }
12777+
12778+ if (!method) {
12779+ libssh2_error(session, LIBSSH2_ERROR_METHOD_NONE,
12780+ "No method negotiated", 0);
12781+ return NULL;
12782+ }
12783+
12784+ return method->name;
12785+}
12786+
12787+/* }}} */
12788+
12789+/* {{{ libssh2_session_abstract
12790+ * Retrieve a pointer to the abstract property
12791+ */
12792+LIBSSH2_API void **
12793+libssh2_session_abstract(LIBSSH2_SESSION * session)
12794+{
12795+ return &session->abstract;
12796+}
12797+
12798+/* }}} */
12799+
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
12804+ */
12805+LIBSSH2_API int
12806+libssh2_session_last_error(LIBSSH2_SESSION * session, char **errmsg,
12807+ int *errmsg_len, int want_buf)
12808+{
12809+ /* No error to report */
12810+ if (!session->err_code) {
12811+ if (errmsg) {
12812+ if (want_buf) {
12813+ *errmsg = LIBSSH2_ALLOC(session, 1);
12814+ if (*errmsg) {
12815+ **errmsg = 0;
12816+ }
12817+ } else {
12818+ *errmsg = (char *) "";
12819+ }
12820+ }
12821+ if (errmsg_len) {
12822+ *errmsg_len = 0;
12823+ }
12824+ return 0;
12825+ }
12826+
12827+ if (errmsg) {
12828+ char *serrmsg = session->err_msg ? session->err_msg : (char *) "";
12829+ int ownbuf = session->err_msg ? session->err_should_free : 0;
12830+
12831+ if (want_buf) {
12832+ if (ownbuf) {
12833+ /* Just give the calling program the buffer */
12834+ *errmsg = serrmsg;
12835+ session->err_should_free = 0;
12836+ } else {
12837+ /* Make a copy so the calling program can own it */
12838+ *errmsg = LIBSSH2_ALLOC(session, session->err_msglen + 1);
12839+ if (*errmsg) {
12840+ memcpy(*errmsg, session->err_msg, session->err_msglen);
12841+ (*errmsg)[session->err_msglen] = 0;
12842+ }
12843+ }
12844+ } else {
12845+ *errmsg = serrmsg;
12846+ }
12847+ }
12848+
12849+ if (errmsg_len) {
12850+ *errmsg_len = session->err_msglen;
12851+ }
12852+
12853+ return session->err_code;
12854+}
12855+
12856+/* }}} */
12857+
12858+/* {{{ libssh2_session_last_error
12859+* Returns error code
12860+*/
12861+LIBSSH2_API int
12862+libssh2_session_last_errno(LIBSSH2_SESSION * session)
12863+{
12864+ return session->err_code;
12865+}
12866+
12867+/* }}} */
12868+
12869+/* {{{ libssh2_session_flag
12870+ * Set/Get session flags
12871+ * Passing flag==0 will avoid changing session->flags while still returning its current value
12872+ */
12873+LIBSSH2_API int
12874+libssh2_session_flag(LIBSSH2_SESSION * session, int flag, int value)
12875+{
12876+ if (value) {
12877+ session->flags |= flag;
12878+ } else {
12879+ session->flags &= ~flag;
12880+ }
12881+
12882+ return session->flags;
12883+}
12884+
12885+/* }}} */
12886+
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.
12890+ */
12891+int
12892+_libssh2_session_set_blocking(LIBSSH2_SESSION * session, int blocking)
12893+{
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 */
12899+ return bl;
12900+ }
12901+ session->socket_block = blocking;
12902+
12903+ _libssh2_nonblock(session->socket_fd, !blocking);
12904+
12905+ return bl;
12906+}
12907+
12908+/* }}} */
12909+
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
12913+ */
12914+LIBSSH2_API void
12915+libssh2_session_set_blocking(LIBSSH2_SESSION * session, int blocking)
12916+{
12917+ (void) _libssh2_session_set_blocking(session, blocking);
12918+}
12919+
12920+/* }}} */
12921+
12922+/* {{{ libssh2_session_get_blocking
12923+* Returns a session's blocking mode on or off
12924+*/
12925+LIBSSH2_API int
12926+libssh2_session_get_blocking(LIBSSH2_SESSION * session)
12927+{
12928+ return session->socket_block;
12929+}
12930+
12931+/* }}} */
12932+
12933+/* {{{ libssh2_poll_channel_read
12934+ * Returns 0 if no data is waiting on channel,
12935+ * non-0 if data is available
12936+ */
12937+LIBSSH2_API int
12938+libssh2_poll_channel_read(LIBSSH2_CHANNEL * channel, int extended)
12939+{
12940+ LIBSSH2_SESSION *session = channel->session;
12941+ LIBSSH2_PACKET *packet = session->packets.head;
12942+
12943+ while (packet)
12944+ {
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 )) {
12949+ return 1;
12950+ } else if ( extended == 0 &&
12951+ packet->data[0] == SSH_MSG_CHANNEL_DATA) {
12952+ return 1;
12953+ }
12954+ /* else - no data of any type is ready to be read */
12955+ }
12956+ packet = packet->next;
12957+ }
12958+
12959+ return 0;
12960+}
12961+
12962+/* }}} */
12963+
12964+/* {{{ libssh2_poll_channel_write
12965+ * Returns 0 if writing to channel would block,
12966+ * non-0 if data can be written without blocking
12967+ */
12968+static inline int
12969+libssh2_poll_channel_write(LIBSSH2_CHANNEL * channel)
12970+{
12971+ return channel->local.window_size ? 1 : 0;
12972+}
12973+
12974+/* }}} */
12975+
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
12979+ */
12980+static inline int
12981+libssh2_poll_listener_queued(LIBSSH2_LISTENER * listener)
12982+{
12983+ return listener->queue ? 1 : 0;
12984+}
12985+
12986+/* }}} */
12987+
12988+/* {{{ libssh2_poll
12989+ * Poll sockets, channels, and listeners for activity
12990+ */
12991+LIBSSH2_API int
12992+libssh2_poll(LIBSSH2_POLLFD * fds, unsigned int nfds, long timeout)
12993+{
12994+ long timeout_remaining;
12995+ unsigned int i, active_fds;
12996+#ifdef HAVE_POLL
12997+ LIBSSH2_SESSION *session = NULL;
12998+#ifdef HAVE_ALLOCA
12999+ struct pollfd *sockets = alloca(sizeof(struct pollfd) * nfds);
13000+#else
13001+ struct pollfd sockets[256];
13002+
13003+ if (nfds > 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 */
13006+ return -1;
13007+#endif
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;
13016+ break;
13017+
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;
13022+ if (!session)
13023+ session = fds[i].fd.channel->session;
13024+ break;
13025+
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;
13030+ if (!session)
13031+ session = fds[i].fd.listener->session;
13032+ break;
13033+
13034+ default:
13035+ if (session)
13036+ libssh2_error(session, LIBSSH2_ERROR_INVALID_POLL_TYPE,
13037+ "Invalid descriptor passed to libssh2_poll()",
13038+ 0);
13039+ return -1;
13040+ }
13041+ }
13042+#elif defined(HAVE_SELECT)
13043+ LIBSSH2_SESSION *session = NULL;
13044+ int maxfd = 0;
13045+ fd_set rfds, wfds;
13046+ struct timeval tv;
13047+
13048+ FD_ZERO(&rfds);
13049+ FD_ZERO(&wfds);
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;
13058+ }
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;
13063+ }
13064+ break;
13065+
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;
13070+ if (!session)
13071+ session = fds[i].fd.channel->session;
13072+ break;
13073+
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;
13078+ if (!session)
13079+ session = fds[i].fd.listener->session;
13080+ break;
13081+
13082+ default:
13083+ if (session)
13084+ libssh2_error(session, LIBSSH2_ERROR_INVALID_POLL_TYPE,
13085+ "Invalid descriptor passed to libssh2_poll()",
13086+ 0);
13087+ return -1;
13088+ }
13089+ }
13090+#else
13091+ /* No select() or poll()
13092+ * no sockets sturcture to setup
13093+ */
13094+
13095+ timeout = 0;
13096+#endif /* HAVE_POLL or HAVE_SELECT */
13097+
13098+ timeout_remaining = timeout;
13099+ do {
13100+#if defined(HAVE_POLL) || defined(HAVE_SELECT)
13101+ int sysret;
13102+#endif
13103+
13104+ active_fds = 0;
13105+
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,
13114+ 0) ?
13115+ LIBSSH2_POLLFD_POLLIN : 0;
13116+ }
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,
13121+ 1) ?
13122+ LIBSSH2_POLLFD_POLLEXT : 0;
13123+ }
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.
13128+ channel) ?
13129+ LIBSSH2_POLLFD_POLLOUT : 0;
13130+ }
13131+ if (fds[i].fd.channel->remote.close
13132+ || fds[i].fd.channel->local.close) {
13133+ fds[i].revents |= LIBSSH2_POLLFD_CHANNEL_CLOSED;
13134+ }
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;
13140+ }
13141+ break;
13142+
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.
13148+ listener) ?
13149+ LIBSSH2_POLLFD_POLLIN : 0;
13150+ }
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;
13156+ }
13157+ break;
13158+ }
13159+ }
13160+ if (fds[i].revents) {
13161+ active_fds++;
13162+ }
13163+ }
13164+
13165+ if (active_fds) {
13166+ /* Don't block on the sockets if we have channels/listeners which are ready */
13167+ timeout_remaining = 0;
13168+ }
13169+#ifdef HAVE_POLL
13170+
13171+#ifdef HAVE_GETTIMEOFDAY
13172+ {
13173+ struct timeval tv_begin, tv_end;
13174+
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;
13180+ }
13181+#else
13182+ /* If the platform doesn't support gettimeofday,
13183+ * then just make the call non-blocking and walk away
13184+ */
13185+ sysret = poll(sockets, nfds, timeout_remaining);
13186+ timeout_remaining = 0;
13187+#endif /* HAVE_GETTIMEOFDAY */
13188+
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) {
13196+ active_fds++;
13197+ }
13198+ break;
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)
13203+ > 0);
13204+ }
13205+ if (sockets[i].revents & POLLHUP) {
13206+ fds[i].revents |=
13207+ LIBSSH2_POLLFD_CHANNEL_CLOSED |
13208+ LIBSSH2_POLLFD_SESSION_CLOSED;
13209+ }
13210+ sockets[i].revents = 0;
13211+ break;
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)
13216+ > 0);
13217+ }
13218+ if (sockets[i].revents & POLLHUP) {
13219+ fds[i].revents |=
13220+ LIBSSH2_POLLFD_LISTENER_CLOSED |
13221+ LIBSSH2_POLLFD_SESSION_CLOSED;
13222+ }
13223+ sockets[i].revents = 0;
13224+ break;
13225+ }
13226+ }
13227+ }
13228+#elif defined(HAVE_SELECT)
13229+ tv.tv_sec = timeout_remaining / 1000;
13230+ tv.tv_usec = (timeout_remaining % 1000) * 1000;
13231+#ifdef HAVE_GETTIMEOFDAY
13232+ {
13233+ struct timeval tv_begin, tv_end;
13234+
13235+ gettimeofday((struct timeval *) &tv_begin, NULL);
13236+ sysret = select(maxfd+1, &rfds, &wfds, NULL, &tv);
13237+ gettimeofday((struct timeval *) &tv_end, NULL);
13238+
13239+ timeout_remaining -= (tv_end.tv_sec - tv_begin.tv_sec) * 1000;
13240+ timeout_remaining -= (tv_end.tv_usec - tv_begin.tv_usec) / 1000;
13241+ }
13242+#else
13243+ /* If the platform doesn't support gettimeofday,
13244+ * then just make the call non-blocking and walk away
13245+ */
13246+ sysret = select(maxfd+1, &rfds, &wfds, NULL, &tv);
13247+ timeout_remaining = 0;
13248+#endif
13249+
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;
13256+ }
13257+ if (FD_ISSET(fds[i].fd.socket, &wfds)) {
13258+ fds[i].revents |= LIBSSH2_POLLFD_POLLOUT;
13259+ }
13260+ if (fds[i].revents) {
13261+ active_fds++;
13262+ }
13263+ break;
13264+
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)
13269+ > 0);
13270+ }
13271+ break;
13272+
13273+ case LIBSSH2_POLLFD_LISTENER:
13274+ if (FD_ISSET
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)
13278+ > 0);
13279+ }
13280+ break;
13281+ }
13282+ }
13283+ }
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);
13286+
13287+ return active_fds;
13288+}
13289+
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
13294+ */
13295+LIBSSH2_API int
13296+libssh2_session_block_directions(LIBSSH2_SESSION *session)
13297+{
13298+ return session->socket_block_directions;
13299+}
13300+
13301+/* }}} */
13302
13303Property changes on: libssh2/src/session.c
13304___________________________________________________________________
13305Added: svn:mime-type
13306 + text/x-c
13307Added: svn:keywords
13308 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
13309Added: cvs2svn:cvs-rev
13310 + 1.3
13311Added: svn:eol-style
13312 + native
13313
13314Index: libssh2/src/openssl.c
13315===================================================================
13316--- libssh2/src/openssl.c (.../tags/RELEASE_0_11_0)
13317+++ libssh2/src/openssl.c (.../trunk)
13318@@ -0,0 +1,316 @@
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>
13322+ *
13323+ * Redistribution and use in source and binary forms,
13324+ * with or without modification, are permitted provided
13325+ * that the following conditions are met:
13326+ *
13327+ * Redistributions of source code must retain the above
13328+ * copyright notice, this list of conditions and the
13329+ * following disclaimer.
13330+ *
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.
13335+ *
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.
13340+ *
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.
13355+ */
13356+
13357+#include "libssh2_priv.h"
13358+#include <string.h>
13359+
13360+#ifndef EVP_MAX_BLOCK_LENGTH
13361+#define EVP_MAX_BLOCK_LENGTH 32
13362+#endif
13363+
13364+int
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)
13381+{
13382+ *rsa = RSA_new();
13383+
13384+ (*rsa)->e = BN_new();
13385+ BN_bin2bn(edata, elen, (*rsa)->e);
13386+
13387+ (*rsa)->n = BN_new();
13388+ BN_bin2bn(ndata, nlen, (*rsa)->n);
13389+
13390+ if (ddata) {
13391+ (*rsa)->d = BN_new();
13392+ BN_bin2bn(ddata, dlen, (*rsa)->d);
13393+
13394+ (*rsa)->p = BN_new();
13395+ BN_bin2bn(pdata, plen, (*rsa)->p);
13396+
13397+ (*rsa)->q = BN_new();
13398+ BN_bin2bn(qdata, qlen, (*rsa)->q);
13399+
13400+ (*rsa)->dmp1 = BN_new();
13401+ BN_bin2bn(e1data, e1len, (*rsa)->dmp1);
13402+
13403+ (*rsa)->dmq1 = BN_new();
13404+ BN_bin2bn(e2data, e2len, (*rsa)->dmq1);
13405+
13406+ (*rsa)->iqmp = BN_new();
13407+ BN_bin2bn(coeffdata, coefflen, (*rsa)->iqmp);
13408+ }
13409+ return 0;
13410+}
13411+
13412+int
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)
13417+{
13418+ unsigned char hash[SHA_DIGEST_LENGTH];
13419+ int ret;
13420+
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;
13425+}
13426+
13427+int
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)
13438+{
13439+ *dsactx = DSA_new();
13440+
13441+ (*dsactx)->p = BN_new();
13442+ BN_bin2bn(p, p_len, (*dsactx)->p);
13443+
13444+ (*dsactx)->q = BN_new();
13445+ BN_bin2bn(q, q_len, (*dsactx)->q);
13446+
13447+ (*dsactx)->g = BN_new();
13448+ BN_bin2bn(g, g_len, (*dsactx)->g);
13449+
13450+ (*dsactx)->pub_key = BN_new();
13451+ BN_bin2bn(y, y_len, (*dsactx)->pub_key);
13452+
13453+ if (x_len) {
13454+ (*dsactx)->priv_key = BN_new();
13455+ BN_bin2bn(x, x_len, (*dsactx)->priv_key);
13456+ }
13457+
13458+ return 0;
13459+}
13460+
13461+int
13462+_libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx,
13463+ const unsigned char *sig,
13464+ const unsigned char *m, unsigned long m_len)
13465+{
13466+ unsigned char hash[SHA_DIGEST_LENGTH];
13467+ DSA_SIG dsasig;
13468+ int ret;
13469+
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);
13474+
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);
13479+
13480+ return (ret == 1) ? 0 : -1;
13481+}
13482+
13483+int
13484+_libssh2_cipher_init(_libssh2_cipher_ctx * h,
13485+ _libssh2_cipher_type(algo),
13486+ unsigned char *iv, unsigned char *secret, int encrypt)
13487+{
13488+ EVP_CIPHER_CTX_init(h);
13489+ EVP_CipherInit(h, algo(), secret, iv, encrypt);
13490+ return 0;
13491+}
13492+
13493+int
13494+_libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx,
13495+ _libssh2_cipher_type(algo),
13496+ int encrypt, unsigned char *block)
13497+{
13498+ int blocksize = ctx->cipher->block_size;
13499+ unsigned char buf[EVP_MAX_BLOCK_LENGTH];
13500+ int ret;
13501+ (void) algo;
13502+ (void) encrypt;
13503+
13504+ if (blocksize == 1) {
13505+/* Hack for arcfour. */
13506+ blocksize = 8;
13507+ }
13508+ ret = EVP_Cipher(ctx, buf, block, blocksize);
13509+ if (ret == 1) {
13510+ memcpy(block, buf, blocksize);
13511+ }
13512+ return ret == 1 ? 0 : 1;
13513+}
13514+
13515+/* TODO: Optionally call a passphrase callback specified by the
13516+ * calling program
13517+ */
13518+static int
13519+passphrase_cb(char *buf, int size, int rwflag, char *passphrase)
13520+{
13521+ int passphrase_len = strlen(passphrase);
13522+ (void) rwflag;
13523+
13524+ if (passphrase_len > (size - 1)) {
13525+ passphrase_len = size - 1;
13526+ }
13527+ memcpy(buf, passphrase, passphrase_len);
13528+ buf[passphrase_len] = '\0';
13529+
13530+ return passphrase_len;
13531+}
13532+
13533+int
13534+_libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa,
13535+ LIBSSH2_SESSION * session,
13536+ FILE * fp, unsigned const char *passphrase)
13537+{
13538+ (void) session;
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.
13543+ */
13544+ OpenSSL_add_all_ciphers();
13545+ }
13546+ *rsa = PEM_read_RSAPrivateKey(fp, NULL, (void *) passphrase_cb,
13547+ (void *) passphrase);
13548+ if (!*rsa) {
13549+ return -1;
13550+ }
13551+ return 0;
13552+}
13553+
13554+int
13555+_libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa,
13556+ LIBSSH2_SESSION * session,
13557+ FILE * fp, unsigned const char *passphrase)
13558+{
13559+ (void) session;
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.
13564+ */
13565+ OpenSSL_add_all_ciphers();
13566+ }
13567+ *dsa = PEM_read_DSAPrivateKey(fp, NULL, (void *) passphrase_cb,
13568+ (void *) passphrase);
13569+ if (!*dsa) {
13570+ return -1;
13571+ }
13572+ return 0;
13573+}
13574+
13575+int
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)
13581+{
13582+ int ret;
13583+ unsigned char *sig;
13584+ unsigned int sig_len;
13585+
13586+ sig_len = RSA_size(rsactx);
13587+ sig = LIBSSH2_ALLOC(session, sig_len);
13588+
13589+ if (!sig) {
13590+ return -1;
13591+ }
13592+
13593+ ret = RSA_sign(NID_sha1, hash, hash_len, sig, &sig_len, rsactx);
13594+
13595+ if (!ret) {
13596+ LIBSSH2_FREE(session, sig);
13597+ return -1;
13598+ }
13599+
13600+ *signature = sig;
13601+ *signature_len = sig_len;
13602+
13603+ return 0;
13604+}
13605+
13606+int
13607+_libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,
13608+ const unsigned char *hash,
13609+ unsigned long hash_len, unsigned char *signature)
13610+{
13611+ DSA_SIG *sig;
13612+ int r_len, s_len, rs_pad;
13613+ (void) hash_len;
13614+
13615+ sig = DSA_do_sign(hash, SHA_DIGEST_LENGTH, dsactx);
13616+ if (!sig) {
13617+ return -1;
13618+ }
13619+
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);
13625+ return -1;
13626+ }
13627+
13628+ BN_bn2bin(sig->r, signature + rs_pad);
13629+ BN_bn2bin(sig->s, signature + rs_pad + r_len);
13630+
13631+ DSA_SIG_free(sig);
13632+
13633+ return 0;
13634+}
13635
13636Property changes on: libssh2/src/openssl.c
13637___________________________________________________________________
13638Added: svn:mime-type
13639 + text/x-c
13640Added: svn:keywords
13641 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
13642Added: cvs2svn:cvs-rev
13643 + 1.1
13644Added: svn:eol-style
13645 + native
13646Added: svn:executable
13647 + *
13648
13649Index: libssh2/src/scp.c
13650===================================================================
13651--- libssh2/src/scp.c (.../tags/RELEASE_0_11_0)
13652+++ libssh2/src/scp.c (.../trunk)
13653@@ -0,0 +1,811 @@
13654+/* Copyright (c) 2004-2008, Sara Golemon <sarag@libssh2.org>
13655+ * All rights reserved.
13656+ *
13657+ * Redistribution and use in source and binary forms,
13658+ * with or without modification, are permitted provided
13659+ * that the following conditions are met:
13660+ *
13661+ * Redistributions of source code must retain the above
13662+ * copyright notice, this list of conditions and the
13663+ * following disclaimer.
13664+ *
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.
13669+ *
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.
13674+ *
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.
13689+ */
13690+
13691+#include "libssh2_priv.h"
13692+#include <errno.h>
13693+#include <stdlib.h>
13694+
13695+/* {{{ libssh2_scp_recv
13696+ * Open a channel and request a remote file via SCP
13697+ *
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.
13701+ */
13702+LIBSSH2_API LIBSSH2_CHANNEL *
13703+libssh2_scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb)
13704+{
13705+ int path_len = strlen(path);
13706+ int rc;
13707+
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;
13713+
13714+ session->scpRecv_command_len = path_len + sizeof("scp -f ");
13715+
13716+ if (sb) {
13717+ session->scpRecv_command_len++;
13718+ }
13719+
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",
13725+ 0);
13726+ return NULL;
13727+ }
13728+ if (sb) {
13729+ memcpy(session->scpRecv_command, "scp -pf ",
13730+ sizeof("scp -pf ") - 1);
13731+ memcpy(session->scpRecv_command + sizeof("scp -pf ") - 1, path,
13732+ path_len);
13733+ } else {
13734+ memcpy(session->scpRecv_command, "scp -f ", sizeof("scp -f ") - 1);
13735+ memcpy(session->scpRecv_command + sizeof("scp -f ") - 1, path,
13736+ path_len);
13737+ }
13738+ session->scpRecv_command[session->scpRecv_command_len - 1] = '\0';
13739+
13740+ _libssh2_debug(session, LIBSSH2_DBG_SCP,
13741+ "Opening channel for SCP receive");
13742+
13743+ session->scpRecv_state = libssh2_NB_state_created;
13744+ }
13745+
13746+ if (session->scpRecv_state == libssh2_NB_state_created) {
13747+ /* Allocate a channel */
13748+ do {
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,
13754+ 0);
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;
13761+ return NULL;
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);
13766+ return NULL;
13767+ }
13768+ }
13769+ } while (!session->scpRecv_channel);
13770+
13771+ session->scpRecv_state = libssh2_NB_state_sent;
13772+ }
13773+
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);
13783+ return NULL;
13784+ } else if (rc) {
13785+ LIBSSH2_FREE(session, session->scpRecv_command);
13786+ session->scpRecv_command = NULL;
13787+ goto scp_recv_error;
13788+ }
13789+ LIBSSH2_FREE(session, session->scpRecv_command);
13790+ session->scpRecv_command = NULL;
13791+
13792+ _libssh2_debug(session, LIBSSH2_DBG_SCP, "Sending initial wakeup");
13793+ /* SCP ACK */
13794+ session->scpRecv_response[0] = '\0';
13795+
13796+ session->scpRecv_state = libssh2_NB_state_sent1;
13797+ }
13798+
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);
13805+ return NULL;
13806+ } else if (rc != 1) {
13807+ goto scp_recv_error;
13808+ }
13809+
13810+ /* Parse SCP response */
13811+ session->scpRecv_response_len = 0;
13812+
13813+ session->scpRecv_state = libssh2_NB_state_sent2;
13814+ }
13815+
13816+ if ((session->scpRecv_state == libssh2_NB_state_sent2)
13817+ || (session->scpRecv_state == libssh2_NB_state_sent3)) {
13818+ while (sb
13819+ && (session->scpRecv_response_len <
13820+ LIBSSH2_SCP_RESPONSE_BUFLEN)) {
13821+ unsigned char *s, *p;
13822+
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);
13831+ return NULL;
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;
13837+ }
13838+ session->scpRecv_response_len++;
13839+
13840+ if (session->scpRecv_response[0] != 'T') {
13841+ /*
13842+ * Set this as the default error for here, if
13843+ * we are successful it will be replaced
13844+ */
13845+ libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
13846+ "Invalid data in SCP response, missing Time data",
13847+ 0);
13848+
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;
13856+ }
13857+ memset(session->scpRecv_err_msg, 0,
13858+ session->scpRecv_err_len + 1);
13859+
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);
13864+ if (rc <= 0) {
13865+ /*
13866+ * Since we have alread started reading this packet, it is
13867+ * already in the systems so it can't return PACKET_EAGAIN
13868+ */
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",
13873+ 0);
13874+ goto scp_recv_error;
13875+ }
13876+
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;
13881+ }
13882+
13883+ if ((session->scpRecv_response_len > 1) &&
13884+ ((session->
13885+ scpRecv_response[session->scpRecv_response_len - 1] <
13886+ '0')
13887+ || (session->
13888+ scpRecv_response[session->scpRecv_response_len - 1] >
13889+ '9'))
13890+ && (session->
13891+ scpRecv_response[session->scpRecv_response_len - 1] !=
13892+ ' ')
13893+ && (session->
13894+ scpRecv_response[session->scpRecv_response_len - 1] !=
13895+ '\r')
13896+ && (session->
13897+ scpRecv_response[session->scpRecv_response_len - 1] !=
13898+ '\n')) {
13899+ libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
13900+ "Invalid data in SCP response", 0);
13901+ goto scp_recv_error;
13902+ }
13903+
13904+ if ((session->scpRecv_response_len < 9)
13905+ || (session->
13906+ scpRecv_response[session->scpRecv_response_len - 1] !=
13907+ '\n')) {
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",
13913+ 0);
13914+ goto scp_recv_error;
13915+ }
13916+ /* Way too short to be an SCP response, or not done yet, short circuit */
13917+ continue;
13918+ }
13919+
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] ==
13923+ '\r')
13924+ || (session->
13925+ scpRecv_response[session->scpRecv_response_len -
13926+ 1] == '\n'))
13927+ session->scpRecv_response_len--;
13928+ session->scpRecv_response[session->scpRecv_response_len] =
13929+ '\0';
13930+
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",
13935+ 0);
13936+ goto scp_recv_error;
13937+ }
13938+
13939+ s = session->scpRecv_response + 1;
13940+
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",
13946+ 0);
13947+ goto scp_recv_error;
13948+ }
13949+
13950+ *(p++) = '\0';
13951+ /* Make sure we don't get fooled by leftover values */
13952+ errno = 0;
13953+ session->scpRecv_mtime = strtol((char *) s, NULL, 10);
13954+ if (errno) {
13955+ libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
13956+ "Invalid response from SCP server, invalid mtime",
13957+ 0);
13958+ goto scp_recv_error;
13959+ }
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",
13965+ 0);
13966+ goto scp_recv_error;
13967+ }
13968+
13969+ /* Ignore mtime.usec */
13970+ s++;
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",
13976+ 0);
13977+ goto scp_recv_error;
13978+ }
13979+
13980+ *(p++) = '\0';
13981+ /* Make sure we don't get fooled by leftover values */
13982+ errno = 0;
13983+ session->scpRecv_atime = strtol((char *) s, NULL, 10);
13984+ if (errno) {
13985+ libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
13986+ "Invalid response from SCP server, invalid atime",
13987+ 0);
13988+ goto scp_recv_error;
13989+ }
13990+
13991+ /* SCP ACK */
13992+ session->scpRecv_response[0] = '\0';
13993+
13994+ session->scpRecv_state = libssh2_NB_state_sent3;
13995+ }
13996+
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);
14004+ return NULL;
14005+ } else if (rc != 1) {
14006+ goto scp_recv_error;
14007+ }
14008+
14009+ _libssh2_debug(session, LIBSSH2_DBG_SCP,
14010+ "mtime = %ld, atime = %ld",
14011+ session->scpRecv_mtime, session->scpRecv_atime);
14012+
14013+ /* We *should* check that atime.usec is valid, but why let that stop use? */
14014+ break;
14015+ }
14016+ }
14017+
14018+ session->scpRecv_state = libssh2_NB_state_sent4;
14019+ }
14020+
14021+ if (session->scpRecv_state == libssh2_NB_state_sent4) {
14022+ session->scpRecv_response_len = 0;
14023+
14024+ session->scpRecv_state = libssh2_NB_state_sent5;
14025+ }
14026+
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;
14031+
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);
14040+ return NULL;
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;
14046+ }
14047+ session->scpRecv_response_len++;
14048+
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;
14053+ }
14054+
14055+ if ((session->scpRecv_response_len > 1) &&
14056+ (session->
14057+ scpRecv_response[session->scpRecv_response_len - 1] !=
14058+ '\r')
14059+ && (session->
14060+ scpRecv_response[session->scpRecv_response_len - 1] !=
14061+ '\n')
14062+ &&
14063+ ((session->
14064+ scpRecv_response[session->scpRecv_response_len - 1] < 32)
14065+ || (session->
14066+ scpRecv_response[session->scpRecv_response_len - 1] >
14067+ 126))) {
14068+ libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
14069+ "Invalid data in SCP response", 0);
14070+ goto scp_recv_error;
14071+ }
14072+
14073+ if ((session->scpRecv_response_len < 7)
14074+ || (session->
14075+ scpRecv_response[session->scpRecv_response_len - 1] !=
14076+ '\n')) {
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",
14082+ 0);
14083+ goto scp_recv_error;
14084+ }
14085+ /* Way too short to be an SCP response, or not done yet, short circuit */
14086+ continue;
14087+ }
14088+
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] ==
14092+ '\r')
14093+ || (session->
14094+ scpRecv_response[session->scpRecv_response_len -
14095+ 1] == '\n')) {
14096+ session->scpRecv_response_len--;
14097+ }
14098+ session->scpRecv_response[session->scpRecv_response_len] =
14099+ '\0';
14100+
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",
14105+ 0);
14106+ goto scp_recv_error;
14107+ }
14108+
14109+ s = (char *) session->scpRecv_response + 1;
14110+
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",
14116+ 0);
14117+ goto scp_recv_error;
14118+ }
14119+
14120+ *(p++) = '\0';
14121+ /* Make sure we don't get fooled by leftover values */
14122+ errno = 0;
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",
14127+ 0);
14128+ goto scp_recv_error;
14129+ }
14130+
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",
14136+ 0);
14137+ goto scp_recv_error;
14138+ }
14139+
14140+ *(s++) = '\0';
14141+ /* Make sure we don't get fooled by leftover values */
14142+ errno = 0;
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",
14147+ 0);
14148+ goto scp_recv_error;
14149+ }
14150+
14151+ /* SCP ACK */
14152+ session->scpRecv_response[0] = '\0';
14153+
14154+ session->scpRecv_state = libssh2_NB_state_sent6;
14155+ }
14156+
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);
14164+ return NULL;
14165+ } else if (rc != 1) {
14166+ goto scp_recv_error;
14167+ }
14168+ _libssh2_debug(session, LIBSSH2_DBG_SCP,
14169+ "mode = 0%lo size = %ld", session->scpRecv_mode,
14170+ session->scpRecv_size);
14171+
14172+ /* We *should* check that basename is valid, but why let that stop us? */
14173+ break;
14174+ }
14175+ }
14176+
14177+ session->scpRecv_state = libssh2_NB_state_sent7;
14178+ }
14179+
14180+ if (sb) {
14181+ memset(sb, 0, sizeof(struct stat));
14182+
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;
14187+ }
14188+
14189+ session->scpRecv_state = libssh2_NB_state_idle;
14190+ return session->scpRecv_channel;
14191+
14192+ scp_recv_error:
14193+ while (libssh2_channel_free(session->scpRecv_channel) == PACKET_EAGAIN);
14194+ session->scpRecv_channel = NULL;
14195+ session->scpRecv_state = libssh2_NB_state_idle;
14196+ return NULL;
14197+}
14198+
14199+/* }}} */
14200+
14201+/* {{{ libssh2_scp_send_ex
14202+ * Send a file using SCP
14203+ *
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.
14207+ */
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)
14211+{
14212+ int path_len = strlen(path);
14213+ unsigned const char *base;
14214+ int rc;
14215+
14216+ if (session->scpSend_state == libssh2_NB_state_idle) {
14217+ session->scpSend_command_len = path_len + sizeof("scp -t ");
14218+
14219+ if (mtime || atime) {
14220+ session->scpSend_command_len++;
14221+ }
14222+
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",
14228+ 0);
14229+ return NULL;
14230+ }
14231+
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,
14236+ path_len);
14237+ } else {
14238+ memcpy(session->scpSend_command, "scp -t ", sizeof("scp -t ") - 1);
14239+ memcpy(session->scpSend_command + sizeof("scp -t ") - 1, path,
14240+ path_len);
14241+ }
14242+ session->scpSend_command[session->scpSend_command_len - 1] = '\0';
14243+
14244+ _libssh2_debug(session, LIBSSH2_DBG_SCP,
14245+ "Opening channel for SCP send");
14246+ /* Allocate a channel */
14247+
14248+ session->scpSend_state = libssh2_NB_state_created;
14249+ }
14250+
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;
14262+ return NULL;
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);
14267+ return NULL;
14268+ }
14269+ }
14270+
14271+ session->scpSend_state = libssh2_NB_state_sent;
14272+ }
14273+
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);
14283+ return NULL;
14284+ } else if (rc) {
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;
14291+ }
14292+ LIBSSH2_FREE(session, session->scpSend_command);
14293+ session->scpSend_command = NULL;
14294+
14295+ session->scpSend_state = libssh2_NB_state_sent1;
14296+ }
14297+
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);
14305+ return NULL;
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;
14310+ }
14311+
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,
14317+ atime);
14318+ _libssh2_debug(session, LIBSSH2_DBG_SCP, "Sent %s",
14319+ session->scpSend_response);
14320+ }
14321+
14322+ session->scpSend_state = libssh2_NB_state_sent2;
14323+ }
14324+
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);
14334+ return NULL;
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;
14339+ }
14340+
14341+ session->scpSend_state = libssh2_NB_state_sent3;
14342+ }
14343+
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,
14348+ 1);
14349+ if (rc == PACKET_EAGAIN) {
14350+ libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
14351+ "Would block waiting for response", 0);
14352+ return NULL;
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;
14357+ }
14358+
14359+ session->scpSend_state = libssh2_NB_state_sent4;
14360+ }
14361+ } else {
14362+ if (session->scpSend_state == libssh2_NB_state_sent2) {
14363+ session->scpSend_state = libssh2_NB_state_sent4;
14364+ }
14365+ }
14366+
14367+ if (session->scpSend_state == libssh2_NB_state_sent4) {
14368+ /* Send mode, size, and basename */
14369+ base = (unsigned char *) strrchr(path, '/');
14370+ if (base) {
14371+ base++;
14372+ } else {
14373+ base = (unsigned char *) path;
14374+ }
14375+
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);
14382+
14383+ session->scpSend_state = libssh2_NB_state_sent5;
14384+ }
14385+
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);
14393+ return NULL;
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;
14398+ }
14399+
14400+ session->scpSend_state = libssh2_NB_state_sent6;
14401+ }
14402+
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);
14410+ return NULL;
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) {
14416+ /*
14417+ * Set this as the default error for here, if
14418+ * we are successful it will be replaced
14419+ */
14420+ libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
14421+ "Invalid ACK response from remote", 0);
14422+
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;
14429+ }
14430+ memset(session->scpSend_err_msg, 0, session->scpSend_err_len + 1);
14431+
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);
14436+ if (rc <= 0) {
14437+ /*
14438+ * Since we have alread started reading this packet, it is
14439+ * already in the systems so it can't return PACKET_EAGAIN
14440+ */
14441+ LIBSSH2_FREE(session, session->scpSend_err_msg);
14442+ session->scpSend_err_msg = NULL;
14443+ goto scp_send_error;
14444+ }
14445+
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;
14450+ }
14451+ }
14452+
14453+ session->scpSend_state = libssh2_NB_state_idle;
14454+
14455+ return session->scpSend_channel;
14456+
14457+ scp_send_error:
14458+ while (libssh2_channel_free(session->scpSend_channel) == PACKET_EAGAIN);
14459+ session->scpSend_channel = NULL;
14460+ session->scpSend_state = libssh2_NB_state_idle;
14461+ return NULL;
14462+}
14463+
14464+/* }}} */
14465
14466Property changes on: libssh2/src/scp.c
14467___________________________________________________________________
14468Added: svn:mime-type
14469 + text/x-c
14470Added: svn:keywords
14471 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
14472Added: cvs2svn:cvs-rev
14473 + 1.2
14474Added: svn:eol-style
14475 + native
14476
14477Index: libssh2/src/hostkey.c
14478===================================================================
14479--- libssh2/src/hostkey.c (.../tags/RELEASE_0_11_0)
14480+++ libssh2/src/hostkey.c (.../trunk)
14481@@ -0,0 +1,455 @@
14482+/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
14483+ * All rights reserved.
14484+ *
14485+ * Redistribution and use in source and binary forms,
14486+ * with or without modification, are permitted provided
14487+ * that the following conditions are met:
14488+ *
14489+ * Redistributions of source code must retain the above
14490+ * copyright notice, this list of conditions and the
14491+ * following disclaimer.
14492+ *
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.
14497+ *
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.
14502+ *
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.
14517+ */
14518+
14519+#include "libssh2_priv.h"
14520+
14521+/* Needed for struct iovec on some platforms */
14522+#ifdef HAVE_SYS_UIO_H
14523+#include <sys/uio.h>
14524+#endif
14525+
14526+#if LIBSSH2_RSA
14527+/* ***********
14528+ * ssh-rsa *
14529+ *********** */
14530+
14531+static int libssh2_hostkey_method_ssh_rsa_dtor(LIBSSH2_SESSION * session,
14532+ void **abstract);
14533+
14534+/* {{{ libssh2_hostkey_method_ssh_rsa_init
14535+ * Initialize the server hostkey working area with e/n pair
14536+ */
14537+static int
14538+libssh2_hostkey_method_ssh_rsa_init(LIBSSH2_SESSION * session,
14539+ const unsigned char *hostkey_data,
14540+ unsigned long hostkey_data_len,
14541+ void **abstract)
14542+{
14543+ libssh2_rsa_ctx *rsactx;
14544+ const unsigned char *s, *e, *n;
14545+ unsigned long len, e_len, n_len;
14546+
14547+ (void) hostkey_data_len;
14548+
14549+ if (*abstract) {
14550+ libssh2_hostkey_method_ssh_rsa_dtor(session, abstract);
14551+ *abstract = NULL;
14552+ }
14553+
14554+ s = hostkey_data;
14555+ len = libssh2_ntohu32(s);
14556+ s += 4;
14557+
14558+ if (len != 7 || strncmp((char *) s, "ssh-rsa", 7) != 0) {
14559+ return -1;
14560+ }
14561+ s += 7;
14562+
14563+ e_len = libssh2_ntohu32(s);
14564+ s += 4;
14565+
14566+ e = s;
14567+ s += e_len;
14568+ n_len = libssh2_ntohu32(s);
14569+ s += 4;
14570+ n = s;
14571+ s += n_len;
14572+
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))
14575+ return -1;
14576+
14577+ *abstract = rsactx;
14578+
14579+ return 0;
14580+}
14581+
14582+/* }}} */
14583+
14584+/* {{{ libssh2_hostkey_method_ssh_rsa_initPEM
14585+ * Load a Private Key from a PEM file
14586+ */
14587+static int
14588+libssh2_hostkey_method_ssh_rsa_initPEM(LIBSSH2_SESSION * session,
14589+ const char *privkeyfile,
14590+ unsigned const char *passphrase,
14591+ void **abstract)
14592+{
14593+ libssh2_rsa_ctx *rsactx;
14594+ FILE *fp;
14595+ int ret;
14596+
14597+ if (*abstract) {
14598+ libssh2_hostkey_method_ssh_rsa_dtor(session, abstract);
14599+ *abstract = NULL;
14600+ }
14601+
14602+ fp = fopen(privkeyfile, "r");
14603+ if (!fp) {
14604+ return -1;
14605+ }
14606+
14607+ ret = _libssh2_rsa_new_private(&rsactx, session, fp, passphrase);
14608+ fclose(fp);
14609+ if (ret) {
14610+ return -1;
14611+ }
14612+
14613+ *abstract = rsactx;
14614+
14615+ return 0;
14616+}
14617+
14618+/* }}} */
14619+
14620+/* {{{ libssh2_hostkey_method_ssh_rsa_sign
14621+ * Verify signature created by remote
14622+ */
14623+static int
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)
14629+{
14630+ libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract);
14631+ (void) session;
14632+
14633+ /* Skip past keyname_len(4) + keyname(7){"ssh-rsa"} + signature_len(4) */
14634+ sig += 15;
14635+ sig_len -= 15;
14636+ return _libssh2_rsa_sha1_verify(rsactx, sig, sig_len, m, m_len);
14637+}
14638+
14639+/* }}} */
14640+
14641+/* {{{ libssh2_hostkey_method_ssh_rsa_signv
14642+ * Construct a signature from an array of vectors
14643+ */
14644+static int
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[],
14650+ void **abstract)
14651+{
14652+ libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract);
14653+ int ret;
14654+ unsigned int i;
14655+ unsigned char hash[SHA_DIGEST_LENGTH];
14656+ libssh2_sha1_ctx ctx;
14657+
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);
14661+ }
14662+ libssh2_sha1_final(ctx, hash);
14663+
14664+ ret = _libssh2_rsa_sha1_sign(session, rsactx, hash, SHA_DIGEST_LENGTH,
14665+ signature, signature_len);
14666+ if (ret) {
14667+ return -1;
14668+ }
14669+
14670+ return 0;
14671+}
14672+
14673+/* }}} */
14674+
14675+/* {{{ libssh2_hostkey_method_ssh_rsa_dtor
14676+ * Shutdown the hostkey
14677+ */
14678+static int
14679+libssh2_hostkey_method_ssh_rsa_dtor(LIBSSH2_SESSION * session, void **abstract)
14680+{
14681+ libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract);
14682+ (void) session;
14683+
14684+ _libssh2_rsa_free(rsactx);
14685+
14686+ *abstract = NULL;
14687+
14688+ return 0;
14689+}
14690+
14691+/* }}} */
14692+
14693+static const LIBSSH2_HOSTKEY_METHOD libssh2_hostkey_method_ssh_rsa = {
14694+ "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,
14702+};
14703+#endif /* LIBSSH2_RSA */
14704+
14705+#if LIBSSH2_DSA
14706+/* ***********
14707+ * ssh-dss *
14708+ *********** */
14709+
14710+static int libssh2_hostkey_method_ssh_dss_dtor(LIBSSH2_SESSION * session,
14711+ void **abstract);
14712+
14713+/* {{{ libssh2_hostkey_method_ssh_dss_init
14714+ * Initialize the server hostkey working area with p/q/g/y set
14715+ */
14716+static int
14717+libssh2_hostkey_method_ssh_dss_init(LIBSSH2_SESSION * session,
14718+ const unsigned char *hostkey_data,
14719+ unsigned long hostkey_data_len,
14720+ void **abstract)
14721+{
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;
14726+
14727+ if (*abstract) {
14728+ libssh2_hostkey_method_ssh_dss_dtor(session, abstract);
14729+ *abstract = NULL;
14730+ }
14731+
14732+ s = hostkey_data;
14733+ len = libssh2_ntohu32(s);
14734+ s += 4;
14735+ if (len != 7 || strncmp((char *) s, "ssh-dss", 7) != 0) {
14736+ return -1;
14737+ }
14738+ s += 7;
14739+
14740+ p_len = libssh2_ntohu32(s);
14741+ s += 4;
14742+ p = s;
14743+ s += p_len;
14744+ q_len = libssh2_ntohu32(s);
14745+ s += 4;
14746+ q = s;
14747+ s += q_len;
14748+ g_len = libssh2_ntohu32(s);
14749+ s += 4;
14750+ g = s;
14751+ s += g_len;
14752+ y_len = libssh2_ntohu32(s);
14753+ s += 4;
14754+ y = s;
14755+ s += y_len;
14756+
14757+ _libssh2_dsa_new(&dsactx, p, p_len, q, q_len, g, g_len, y, y_len, NULL, 0);
14758+
14759+ *abstract = dsactx;
14760+
14761+ return 0;
14762+}
14763+
14764+/* }}} */
14765+
14766+/* {{{ libssh2_hostkey_method_ssh_dss_initPEM
14767+ * Load a Private Key from a PEM file
14768+ */
14769+static int
14770+libssh2_hostkey_method_ssh_dss_initPEM(LIBSSH2_SESSION * session,
14771+ const char *privkeyfile,
14772+ unsigned const char *passphrase,
14773+ void **abstract)
14774+{
14775+ libssh2_dsa_ctx *dsactx;
14776+ FILE *fp;
14777+ int ret;
14778+
14779+ if (*abstract) {
14780+ libssh2_hostkey_method_ssh_dss_dtor(session, abstract);
14781+ *abstract = NULL;
14782+ }
14783+
14784+ fp = fopen(privkeyfile, "r");
14785+ if (!fp) {
14786+ return -1;
14787+ }
14788+
14789+ ret = _libssh2_dsa_new_private(&dsactx, session, fp, passphrase);
14790+ fclose(fp);
14791+ if (ret) {
14792+ return -1;
14793+ }
14794+
14795+ *abstract = dsactx;
14796+
14797+ return 0;
14798+}
14799+
14800+/* }}} */
14801+
14802+/* {{{ libssh2_hostkey_method_ssh_dss_sign
14803+ * Verify signature created by remote
14804+ */
14805+static int
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)
14811+{
14812+ libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx *) (*abstract);
14813+
14814+ /* Skip past keyname_len(4) + keyname(7){"ssh-dss"} + signature_len(4) */
14815+ sig += 15;
14816+ sig_len -= 15;
14817+ if (sig_len != 40) {
14818+ libssh2_error(session, LIBSSH2_ERROR_PROTO,
14819+ "Invalid DSS signature length", 0);
14820+ return -1;
14821+ }
14822+ return _libssh2_dsa_sha1_verify(dsactx, sig, m, m_len);
14823+}
14824+
14825+/* }}} */
14826+
14827+/* {{{ libssh2_hostkey_method_ssh_dss_signv
14828+ * Construct a signature from an array of vectors
14829+ */
14830+static int
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[],
14836+ void **abstract)
14837+{
14838+ libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx *) (*abstract);
14839+ unsigned char hash[SHA_DIGEST_LENGTH];
14840+ libssh2_sha1_ctx ctx;
14841+ unsigned int i;
14842+
14843+ *signature = LIBSSH2_ALLOC(session, 2 * SHA_DIGEST_LENGTH);
14844+ if (!*signature) {
14845+ return -1;
14846+ }
14847+
14848+ *signature_len = 2 * SHA_DIGEST_LENGTH;
14849+ memset(*signature, 0, 2 * SHA_DIGEST_LENGTH);
14850+
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);
14854+ }
14855+ libssh2_sha1_final(ctx, hash);
14856+
14857+ if (_libssh2_dsa_sha1_sign(dsactx, hash, SHA_DIGEST_LENGTH, *signature)) {
14858+ LIBSSH2_FREE(session, *signature);
14859+ return -1;
14860+ }
14861+
14862+ return 0;
14863+}
14864+
14865+/* }}} */
14866+
14867+/* {{{ libssh2_hostkey_method_ssh_dss_dtor
14868+ * Shutdown the hostkey method
14869+ */
14870+static int
14871+libssh2_hostkey_method_ssh_dss_dtor(LIBSSH2_SESSION * session, void **abstract)
14872+{
14873+ libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx *) (*abstract);
14874+ (void) session;
14875+
14876+ _libssh2_dsa_free(dsactx);
14877+
14878+ *abstract = NULL;
14879+
14880+ return 0;
14881+}
14882+
14883+/* }}} */
14884+
14885+static const LIBSSH2_HOSTKEY_METHOD libssh2_hostkey_method_ssh_dss = {
14886+ "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,
14894+};
14895+#endif /* LIBSSH2_DSA */
14896+
14897+static const LIBSSH2_HOSTKEY_METHOD *_libssh2_hostkey_methods[] = {
14898+#if LIBSSH2_RSA
14899+ &libssh2_hostkey_method_ssh_rsa,
14900+#endif /* LIBSSH2_RSA */
14901+#if LIBSSH2_DSA
14902+ &libssh2_hostkey_method_ssh_dss,
14903+#endif /* LIBSSH2_DSA */
14904+ NULL
14905+};
14906+
14907+const LIBSSH2_HOSTKEY_METHOD **
14908+libssh2_hostkey_methods(void)
14909+{
14910+ return _libssh2_hostkey_methods;
14911+}
14912+
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
14918+ */
14919+LIBSSH2_API const char *
14920+libssh2_hostkey_hash(LIBSSH2_SESSION * session, int hash_type)
14921+{
14922+ switch (hash_type) {
14923+#if LIBSSH2_MD5
14924+ case LIBSSH2_HOSTKEY_HASH_MD5:
14925+ return (char *) session->server_hostkey_md5;
14926+ break;
14927+#endif /* LIBSSH2_MD5 */
14928+ case LIBSSH2_HOSTKEY_HASH_SHA1:
14929+ return (char *) session->server_hostkey_sha1;
14930+ break;
14931+ default:
14932+ return NULL;
14933+ }
14934+}
14935+
14936+/* }}} */
14937
14938Property changes on: libssh2/src/hostkey.c
14939___________________________________________________________________
14940Added: svn:mime-type
14941 + text/x-c
14942Added: svn:keywords
14943 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
14944Added: cvs2svn:cvs-rev
14945 + 1.2
14946Added: svn:eol-style
14947 + native
14948
14949Index: libssh2/src/publickey.c
14950===================================================================
14951--- libssh2/src/publickey.c (.../tags/RELEASE_0_11_0)
14952+++ libssh2/src/publickey.c (.../trunk)
14953@@ -0,0 +1,1094 @@
14954+/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
14955+ * All rights reserved.
14956+ *
14957+ * Redistribution and use in source and binary forms,
14958+ * with or without modification, are permitted provided
14959+ * that the following conditions are met:
14960+ *
14961+ * Redistributions of source code must retain the above
14962+ * copyright notice, this list of conditions and the
14963+ * following disclaimer.
14964+ *
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.
14969+ *
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.
14974+ *
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.
14989+ */
14990+
14991+#include "libssh2_priv.h"
14992+#include "libssh2_publickey.h"
14993+
14994+#define LIBSSH2_PUBLICKEY_VERSION 2
14995+
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
15000+
15001+typedef struct _LIBSSH2_PUBLICKEY_CODE_LIST
15002+{
15003+ int code;
15004+ const char *name;
15005+ int name_len;
15006+} LIBSSH2_PUBLICKEY_CODE_LIST;
15007+
15008+static const LIBSSH2_PUBLICKEY_CODE_LIST libssh2_publickey_response_codes[] = {
15009+ {LIBSSH2_PUBLICKEY_RESPONSE_STATUS, "status", sizeof("status") - 1}
15010+ ,
15011+ {LIBSSH2_PUBLICKEY_RESPONSE_VERSION, "version", sizeof("version") - 1}
15012+ ,
15013+ {LIBSSH2_PUBLICKEY_RESPONSE_PUBLICKEY, "publickey", sizeof("publickey") - 1}
15014+ ,
15015+ {0, NULL, 0}
15016+};
15017+
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
15028+
15029+#define LIBSSH2_PUBLICKEY_STATUS_CODE_MAX 8
15030+
15031+static const LIBSSH2_PUBLICKEY_CODE_LIST libssh2_publickey_status_codes[] = {
15032+ {LIBSSH2_PUBLICKEY_SUCCESS, "success", sizeof("success") - 1}
15033+ ,
15034+ {LIBSSH2_PUBLICKEY_ACCESS_DENIED, "access denied",
15035+ sizeof("access denied") - 1}
15036+ ,
15037+ {LIBSSH2_PUBLICKEY_STORAGE_EXCEEDED, "storage exceeded",
15038+ sizeof("storage exceeded") - 1}
15039+ ,
15040+ {LIBSSH2_PUBLICKEY_VERSION_NOT_SUPPORTED, "version not supported",
15041+ sizeof("version not supported") - 1}
15042+ ,
15043+ {LIBSSH2_PUBLICKEY_KEY_NOT_FOUND, "key not found",
15044+ sizeof("key not found") - 1}
15045+ ,
15046+ {LIBSSH2_PUBLICKEY_KEY_NOT_SUPPORTED, "key not supported",
15047+ sizeof("key not supported") - 1}
15048+ ,
15049+ {LIBSSH2_PUBLICKEY_KEY_ALREADY_PRESENT, "key already present",
15050+ sizeof("key already present") - 1}
15051+ ,
15052+ {LIBSSH2_PUBLICKEY_GENERAL_FAILURE, "general failure",
15053+ sizeof("general failure") - 1}
15054+ ,
15055+ {LIBSSH2_PUBLICKEY_REQUEST_NOT_SUPPORTED, "request not supported",
15056+ sizeof("request not supported") - 1}
15057+ ,
15058+ {0, NULL, 0}
15059+};
15060+
15061+/* {{{ libssh2_publickey_status_error
15062+ * Format an error message from a status code
15063+ */
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 "\""
15067+static void
15068+libssh2_publickey_status_error(const LIBSSH2_PUBLICKEY * pkey,
15069+ LIBSSH2_SESSION * session, int status,
15070+ const unsigned char *message, int message_len)
15071+{
15072+ const char *status_text;
15073+ int status_text_len;
15074+ char *m, *s;
15075+ int m_len;
15076+
15077+ /* GENERAL_FAILURE got remapped between version 1 and 2 */
15078+ if (status == 6 && pkey && pkey->version == 1) {
15079+ status = 7;
15080+ }
15081+
15082+ if (status < 0 || status > LIBSSH2_PUBLICKEY_STATUS_CODE_MAX) {
15083+ status_text = "unknown";
15084+ status_text_len = sizeof("unknown") - 1;
15085+ } else {
15086+ status_text = libssh2_publickey_status_codes[status].name;
15087+ status_text_len = libssh2_publickey_status_codes[status].name_len;
15088+ }
15089+
15090+ m_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);
15095+ if (!m) {
15096+ libssh2_error(session, LIBSSH2_ERROR_ALLOC,
15097+ "Unable to allocate memory for status message", 0);
15098+ return;
15099+ }
15100+ s = m;
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);
15115+}
15116+
15117+/* }}} */
15118+
15119+/* {{{ libssh2_publickey_packet_receive
15120+ * Read a packet from the subsystem
15121+ */
15122+static int
15123+libssh2_publickey_packet_receive(LIBSSH2_PUBLICKEY * pkey,
15124+ unsigned char **data, unsigned long *data_len)
15125+{
15126+ LIBSSH2_CHANNEL *channel = pkey->channel;
15127+ LIBSSH2_SESSION *session = channel->session;
15128+ unsigned char buffer[4];
15129+ int rc;
15130+
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);
15138+ return -1;
15139+ }
15140+
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);
15147+ return -1;
15148+ }
15149+
15150+ pkey->receive_state = libssh2_NB_state_sent;
15151+ }
15152+
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",
15161+ 0);
15162+ LIBSSH2_FREE(session, pkey->receive_packet);
15163+ pkey->receive_packet = NULL;
15164+ pkey->receive_state = libssh2_NB_state_idle;
15165+ return -1;
15166+ }
15167+
15168+ *data = pkey->receive_packet;
15169+ *data_len = pkey->receive_packet_len;
15170+ }
15171+
15172+ pkey->receive_state = libssh2_NB_state_idle;
15173+
15174+ return 0;
15175+}
15176+
15177+/* }}} */
15178+
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
15182+ */
15183+static int
15184+libssh2_publickey_response_id(unsigned char **pdata, int data_len)
15185+{
15186+ unsigned long response_len;
15187+ unsigned char *data = *pdata;
15188+ const LIBSSH2_PUBLICKEY_CODE_LIST *codes =
15189+ libssh2_publickey_response_codes;
15190+
15191+ if (data_len < 4) {
15192+ /* Malformed response */
15193+ return -1;
15194+ }
15195+ response_len = libssh2_ntohu32(data);
15196+ data += 4;
15197+ data_len -= 4;
15198+ if (data_len < (int)response_len) {
15199+ /* Malformed response */
15200+ return -1;
15201+ }
15202+
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;
15208+ }
15209+ codes++;
15210+ }
15211+
15212+ return -1;
15213+}
15214+
15215+/* }}} */
15216+
15217+/* {{{ libssh2_publickey_response_success
15218+ * Generic helper routine to wait for success response and nothing else
15219+ */
15220+static int
15221+libssh2_publickey_response_success(LIBSSH2_PUBLICKEY * pkey)
15222+{
15223+ LIBSSH2_SESSION *session = pkey->channel->session;
15224+ unsigned char *data, *s;
15225+ unsigned long data_len;
15226+ int response;
15227+ int rc;
15228+
15229+ while (1) {
15230+ rc = libssh2_publickey_packet_receive(pkey, &data, &data_len);
15231+ if (rc == PACKET_EAGAIN) {
15232+ return PACKET_EAGAIN;
15233+ } else if (rc) {
15234+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
15235+ "Timeout waiting for response from publickey subsystem",
15236+ 0);
15237+ return -1;
15238+ }
15239+
15240+ s = data;
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);
15245+ return -1;
15246+ }
15247+
15248+ switch (response) {
15249+ case LIBSSH2_PUBLICKEY_RESPONSE_STATUS:
15250+ /* Error, or processing complete */
15251+ {
15252+ unsigned long status, descr_len, lang_len;
15253+ unsigned char *descr, *lang;
15254+
15255+ status = libssh2_ntohu32(s);
15256+ s += 4;
15257+ descr_len = libssh2_ntohu32(s);
15258+ s += 4;
15259+ descr = s;
15260+ s += descr_len;
15261+ lang_len = libssh2_ntohu32(s);
15262+ s += 4;
15263+ lang = s;
15264+ s += lang_len;
15265+
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);
15270+ return -1;
15271+ }
15272+
15273+ if (status == LIBSSH2_PUBLICKEY_SUCCESS) {
15274+ LIBSSH2_FREE(session, data);
15275+ return 0;
15276+ }
15277+
15278+ libssh2_publickey_status_error(pkey, session, status, descr,
15279+ descr_len);
15280+ LIBSSH2_FREE(session, data);
15281+ return -1;
15282+ }
15283+ default:
15284+ /* Unknown/Unexpected */
15285+ libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
15286+ "Unexpected publickey subsystem response, ignoring",
15287+ 0);
15288+ LIBSSH2_FREE(session, data);
15289+ data = NULL;
15290+ }
15291+ }
15292+ /* never reached, but include `return` to silence compiler warnings */
15293+ return -1;
15294+}
15295+
15296+/* }}} */
15297+
15298+
15299+/* *****************
15300+ * Publickey API *
15301+ ***************** */
15302+
15303+/* {{{ libssh2_publickey_init
15304+ * Startup the publickey subsystem
15305+ */
15306+LIBSSH2_API LIBSSH2_PUBLICKEY *
15307+libssh2_publickey_init(LIBSSH2_SESSION * session)
15308+{
15309+ /* 19 = packet_len(4) + version_len(4) + "version"(7) + version_num(4) */
15310+ unsigned char buffer[19];
15311+ unsigned char *s;
15312+ int response;
15313+ int rc;
15314+
15315+ if (session->pkeyInit_state == libssh2_NB_state_idle) {
15316+ session->pkeyInit_data = NULL;
15317+ session->pkeyInit_pkey = NULL;
15318+ session->pkeyInit_channel = NULL;
15319+
15320+ _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY,
15321+ "Initializing publickey subsystem");
15322+
15323+ session->pkeyInit_state = libssh2_NB_state_allocated;
15324+ }
15325+
15326+ if (session->pkeyInit_state == libssh2_NB_state_allocated) {
15327+ do {
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,
15333+ 0);
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);
15340+ return NULL;
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);
15346+ goto err_exit;
15347+ }
15348+ } while (!session->pkeyInit_channel);
15349+
15350+ session->pkeyInit_state = libssh2_NB_state_sent;
15351+ }
15352+
15353+ if (session->pkeyInit_state == libssh2_NB_state_sent) {
15354+ rc = libssh2_channel_process_startup(session->pkeyInit_channel,
15355+ "subsystem",
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);
15361+ return NULL;
15362+ } else if (rc) {
15363+ libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE,
15364+ "Unable to request publickey subsystem", 0);
15365+ goto err_exit;
15366+ }
15367+
15368+ session->pkeyInit_state = libssh2_NB_state_sent1;
15369+ }
15370+
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);
15377+ return NULL;
15378+ }
15379+
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);
15385+ goto err_exit;
15386+ }
15387+ memset(session->pkeyInit_pkey, 0, sizeof(LIBSSH2_PUBLICKEY));
15388+ session->pkeyInit_pkey->channel = session->pkeyInit_channel;
15389+ session->pkeyInit_pkey->version = 0;
15390+
15391+ s = buffer;
15392+ libssh2_htonu32(s, 4 + (sizeof("version") - 1) + 4);
15393+ s += 4;
15394+ libssh2_htonu32(s, sizeof("version") - 1);
15395+ s += 4;
15396+ memcpy(s, "version", sizeof("version") - 1);
15397+ s += sizeof("version") - 1;
15398+ libssh2_htonu32(s, LIBSSH2_PUBLICKEY_VERSION);
15399+ s += 4;
15400+
15401+ _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY,
15402+ "Sending publickey version packet advertising version %d support",
15403+ (int) LIBSSH2_PUBLICKEY_VERSION);
15404+
15405+ session->pkeyInit_state = libssh2_NB_state_sent2;
15406+ }
15407+
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);
15414+ return NULL;
15415+ } else if ((s - buffer) != rc) {
15416+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
15417+ "Unable to send publickey version packet", 0);
15418+ goto err_exit;
15419+ }
15420+
15421+ session->pkeyInit_state = libssh2_NB_state_sent3;
15422+ }
15423+
15424+ if (session->pkeyInit_state == libssh2_NB_state_sent3) {
15425+ while (1) {
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",
15432+ 0);
15433+ return NULL;
15434+ } else if (rc) {
15435+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
15436+ "Timeout waiting for response from publickey subsystem",
15437+ 0);
15438+ goto err_exit;
15439+ }
15440+
15441+ s = session->pkeyInit_data;
15442+ if ((response =
15443+ libssh2_publickey_response_id(&s,
15444+ session->pkeyInit_data_len)) <
15445+ 0) {
15446+ libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
15447+ "Invalid publickey subsystem response code", 0);
15448+ goto err_exit;
15449+ }
15450+
15451+ switch (response) {
15452+ case LIBSSH2_PUBLICKEY_RESPONSE_STATUS:
15453+ /* Error */
15454+ {
15455+ unsigned long status, descr_len, lang_len;
15456+ unsigned char *descr, *lang;
15457+
15458+ status = libssh2_ntohu32(s);
15459+ s += 4;
15460+ descr_len = libssh2_ntohu32(s);
15461+ s += 4;
15462+ descr = s;
15463+ s += descr_len;
15464+ lang_len = libssh2_ntohu32(s);
15465+ s += 4;
15466+ lang = s;
15467+ s += lang_len;
15468+
15469+ if (s >
15470+ session->pkeyInit_data + session->pkeyInit_data_len) {
15471+ libssh2_error(session,
15472+ LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
15473+ "Malformed publickey subsystem packet",
15474+ 0);
15475+ goto err_exit;
15476+ }
15477+
15478+ libssh2_publickey_status_error(NULL, session, status,
15479+ descr, descr_len);
15480+ goto err_exit;
15481+ }
15482+
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;
15493+ }
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;
15501+
15502+ default:
15503+ /* Unknown/Unexpected */
15504+ libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
15505+ "Unexpected publickey subsystem response, ignoring",
15506+ 0);
15507+ LIBSSH2_FREE(session, session->pkeyInit_data);
15508+ session->pkeyInit_data = NULL;
15509+ }
15510+ }
15511+ }
15512+
15513+ /* Never reached except by direct goto */
15514+ err_exit:
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);
15521+ return NULL;
15522+ }
15523+ }
15524+ if (session->pkeyInit_pkey) {
15525+ LIBSSH2_FREE(session, session->pkeyInit_pkey);
15526+ session->pkeyInit_pkey = NULL;
15527+ }
15528+ if (session->pkeyInit_data) {
15529+ LIBSSH2_FREE(session, session->pkeyInit_data);
15530+ session->pkeyInit_data = NULL;
15531+ }
15532+ session->pkeyInit_state = libssh2_NB_state_idle;
15533+ return NULL;
15534+}
15535+
15536+/* }}} */
15537+
15538+/* {{{ libssh2_publickey_add_ex
15539+ * Add a new public key entry
15540+ */
15541+LIBSSH2_API int
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[])
15547+{
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;
15554+ int rc;
15555+
15556+ if (pkey->add_state == libssh2_NB_state_idle) {
15557+ pkey->add_packet = NULL;
15558+
15559+ _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Adding %s publickey",
15560+ name);
15561+
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;
15570+ break;
15571+ }
15572+ }
15573+ packet_len += 4 + comment_len;
15574+ } else {
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) */
15579+ }
15580+ }
15581+
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",
15586+ 0);
15587+ return -1;
15588+ }
15589+
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;
15600+ if (comment) {
15601+ memcpy(pkey->add_s, comment, comment_len);
15602+ pkey->add_s += comment_len;
15603+ }
15604+
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;
15613+ } else {
15614+ /* Version == 2 */
15615+
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;
15637+ }
15638+ }
15639+
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);
15643+
15644+ pkey->add_state = libssh2_NB_state_created;
15645+ }
15646+
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;
15657+ return -1;
15658+ }
15659+ LIBSSH2_FREE(session, pkey->add_packet);
15660+ pkey->add_packet = NULL;
15661+
15662+ pkey->add_state = libssh2_NB_state_sent;
15663+ }
15664+
15665+ rc = libssh2_publickey_response_success(pkey);
15666+ if (rc == PACKET_EAGAIN) {
15667+ return PACKET_EAGAIN;
15668+ }
15669+
15670+ pkey->add_state = libssh2_NB_state_idle;
15671+
15672+ return rc;
15673+}
15674+
15675+/* }}} */
15676+
15677+/* {{{ libssh2_publickey_remove_ex
15678+ * Remove an existing publickey so that authentication can no longer be performed using it
15679+ */
15680+LIBSSH2_API int
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)
15684+{
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;
15689+ int rc;
15690+
15691+ if (pkey->remove_state == libssh2_NB_state_idle) {
15692+ pkey->remove_packet = NULL;
15693+
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",
15698+ 0);
15699+ return -1;
15700+ }
15701+
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;
15717+
15718+ _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY,
15719+ "Sending publickey \"remove\" packet: type=%s blob_len=%ld",
15720+ name, blob_len);
15721+
15722+ pkey->remove_state = libssh2_NB_state_created;
15723+ }
15724+
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;
15736+ return -1;
15737+ }
15738+ LIBSSH2_FREE(session, pkey->remove_packet);
15739+ pkey->remove_packet = NULL;
15740+
15741+ pkey->remove_state = libssh2_NB_state_sent;
15742+ }
15743+
15744+ rc = libssh2_publickey_response_success(pkey);
15745+ if (rc == PACKET_EAGAIN) {
15746+ return PACKET_EAGAIN;
15747+ }
15748+
15749+ pkey->remove_state = libssh2_NB_state_idle;
15750+
15751+ return rc;
15752+}
15753+
15754+/* }}} */
15755+
15756+/* {{{ libssh2_publickey_list_fetch
15757+ * Fetch a list of supported public key from a server
15758+ */
15759+LIBSSH2_API int
15760+libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY * pkey, unsigned long *num_keys,
15761+ libssh2_publickey_list ** pkey_list)
15762+{
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) */
15768+ int response;
15769+ int rc;
15770+
15771+ if (pkey->listFetch_state == libssh2_NB_state_idle) {
15772+ pkey->listFetch_data = NULL;
15773+
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;
15781+
15782+ _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY,
15783+ "Sending publickey \"list\" packet");
15784+
15785+ pkey->listFetch_state = libssh2_NB_state_created;
15786+ }
15787+
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;
15799+ return -1;
15800+ }
15801+
15802+ pkey->listFetch_state = libssh2_NB_state_sent;
15803+ }
15804+
15805+ while (1) {
15806+ rc = libssh2_publickey_packet_receive(pkey, &pkey->listFetch_data,
15807+ &pkey->listFetch_data_len);
15808+ if (rc == PACKET_EAGAIN) {
15809+ return PACKET_EAGAIN;
15810+ } else if (rc) {
15811+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
15812+ "Timeout waiting for response from publickey subsystem",
15813+ 0);
15814+ goto err_exit;
15815+ }
15816+
15817+ pkey->listFetch_s = pkey->listFetch_data;
15818+ if ((response =
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);
15823+ goto err_exit;
15824+ }
15825+
15826+ switch (response) {
15827+ case LIBSSH2_PUBLICKEY_RESPONSE_STATUS:
15828+ /* Error, or processing complete */
15829+ {
15830+ unsigned long status, descr_len, lang_len;
15831+ unsigned char *descr, *lang;
15832+
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;
15843+
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);
15848+ goto err_exit;
15849+ }
15850+
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;
15857+ return 0;
15858+ }
15859+
15860+ libssh2_publickey_status_error(pkey, session, status, descr,
15861+ descr_len);
15862+ goto err_exit;
15863+ }
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 */
15869+ max_keys += 8;
15870+ newlist =
15871+ LIBSSH2_REALLOC(session, list,
15872+ (max_keys +
15873+ 1) * sizeof(libssh2_publickey_list));
15874+ if (!newlist) {
15875+ libssh2_error(session, LIBSSH2_ERROR_ALLOC,
15876+ "Unable to allocate memory for publickey list",
15877+ 0);
15878+ goto err_exit;
15879+ }
15880+ list = newlist;
15881+ }
15882+ if (pkey->version == 1) {
15883+ unsigned long comment_len;
15884+
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",
15895+ 0);
15896+ goto err_exit;
15897+ }
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;
15903+
15904+ pkey->listFetch_s += comment_len;
15905+ } else {
15906+ list[keys].num_attrs = 0;
15907+ list[keys].attrs = NULL;
15908+ }
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;
15917+ } else {
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",
15937+ 0);
15938+ goto err_exit;
15939+ }
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 */
15952+ }
15953+ } else {
15954+ list[keys].attrs = NULL;
15955+ }
15956+ }
15957+ list[keys].packet = pkey->listFetch_data; /* To be FREEd in libssh2_publickey_list_free() */
15958+ keys++;
15959+
15960+ list[keys].packet = NULL; /* Terminate the list */
15961+ pkey->listFetch_data = NULL;
15962+ break;
15963+ default:
15964+ /* Unknown/Unexpected */
15965+ libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
15966+ "Unexpected publickey subsystem response, ignoring",
15967+ 0);
15968+ LIBSSH2_FREE(session, pkey->listFetch_data);
15969+ pkey->listFetch_data = NULL;
15970+ }
15971+ }
15972+
15973+ /* Only reached via explicit goto */
15974+ err_exit:
15975+ if (pkey->listFetch_data) {
15976+ LIBSSH2_FREE(session, pkey->listFetch_data);
15977+ pkey->listFetch_data = NULL;
15978+ }
15979+ if (list) {
15980+ libssh2_publickey_list_free(pkey, list);
15981+ }
15982+ pkey->listFetch_state = libssh2_NB_state_idle;
15983+ return -1;
15984+}
15985+
15986+/* }}} */
15987+
15988+/* {{{ libssh2_publickey_list_free
15989+ * Free a previously fetched list of public keys
15990+ */
15991+LIBSSH2_API void
15992+libssh2_publickey_list_free(LIBSSH2_PUBLICKEY * pkey,
15993+ libssh2_publickey_list * pkey_list)
15994+{
15995+ LIBSSH2_SESSION *session = pkey->channel->session;
15996+ libssh2_publickey_list *p = pkey_list;
15997+
15998+ while (p->packet) {
15999+ if (p->attrs) {
16000+ LIBSSH2_FREE(session, p->attrs);
16001+ }
16002+ LIBSSH2_FREE(session, p->packet);
16003+ p++;
16004+ }
16005+
16006+ LIBSSH2_FREE(session, pkey_list);
16007+}
16008+
16009+/* }}} */
16010+
16011+/* {{{ libssh2_publickey_shutdown
16012+ * Shutdown the publickey subsystem
16013+ */
16014+LIBSSH2_API int
16015+libssh2_publickey_shutdown(LIBSSH2_PUBLICKEY * pkey)
16016+{
16017+ LIBSSH2_SESSION *session = pkey->channel->session;
16018+
16019+ /*
16020+ * Make sure all memory used in the state variables are free
16021+ */
16022+ if (pkey->receive_packet) {
16023+ LIBSSH2_FREE(session, pkey->receive_packet);
16024+ pkey->receive_packet = NULL;
16025+ }
16026+ if (pkey->add_packet) {
16027+ LIBSSH2_FREE(session, pkey->add_packet);
16028+ pkey->add_packet = NULL;
16029+ }
16030+ if (pkey->remove_packet) {
16031+ LIBSSH2_FREE(session, pkey->remove_packet);
16032+ pkey->remove_packet = NULL;
16033+ }
16034+ if (pkey->listFetch_data) {
16035+ LIBSSH2_FREE(session, pkey->listFetch_data);
16036+ pkey->listFetch_data = NULL;
16037+ }
16038+
16039+ if (libssh2_channel_free(pkey->channel) == PACKET_EAGAIN) {
16040+ return PACKET_EAGAIN;
16041+ }
16042+
16043+ LIBSSH2_FREE(session, pkey);
16044+ return 0;
16045+}
16046+
16047+/* }}} */
16048
16049Property changes on: libssh2/src/publickey.c
16050___________________________________________________________________
16051Added: svn:mime-type
16052 + text/x-c
16053Added: svn:keywords
16054 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
16055Added: cvs2svn:cvs-rev
16056 + 1.4
16057Added: svn:eol-style
16058 + native
16059
16060Index: libssh2/src/kex.c
16061===================================================================
16062--- libssh2/src/kex.c (.../tags/RELEASE_0_11_0)
16063+++ libssh2/src/kex.c (.../trunk)
16064@@ -0,0 +1,1916 @@
16065+/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
16066+ * All rights reserved.
16067+ *
16068+ * Redistribution and use in source and binary forms,
16069+ * with or without modification, are permitted provided
16070+ * that the following conditions are met:
16071+ *
16072+ * Redistributions of source code must retain the above
16073+ * copyright notice, this list of conditions and the
16074+ * following disclaimer.
16075+ *
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.
16080+ *
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.
16085+ *
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.
16100+ */
16101+
16102+#include "libssh2_priv.h"
16103+
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) \
16107+{ \
16108+ libssh2_sha1_ctx hash; \
16109+ unsigned long len = 0; \
16110+ if (!(value)) { \
16111+ value = LIBSSH2_ALLOC(session, reqlen + SHA_DIGEST_LENGTH); \
16112+ } \
16113+ if (value) \
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); \
16120+ if (len > 0) { \
16121+ libssh2_sha1_update(hash, value, len); \
16122+ } else { \
16123+ libssh2_sha1_update(hash, (version), 1); \
16124+ libssh2_sha1_update(hash, session->session_id, \
16125+ session->session_id_len); \
16126+ } \
16127+ libssh2_sha1_final(hash, (value) + len); \
16128+ len += SHA_DIGEST_LENGTH; \
16129+ } \
16130+}
16131+
16132+/* {{{ libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange
16133+ * Diffie Hellman Key Exchange, Group Agnostic
16134+ */
16135+static int
16136+libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *
16137+ session,
16138+ _libssh2_bn * g,
16139+ _libssh2_bn * p,
16140+ int group_order,
16141+ unsigned char
16142+ packet_type_init,
16143+ unsigned char
16144+ packet_type_reply,
16145+ unsigned char
16146+ *midhash,
16147+ unsigned long
16148+ midhash_len,
16149+ kmdhgGPsha1kex_state_t
16150+ * exchange_state)
16151+{
16152+ int ret = 0;
16153+ int rc;
16154+
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 */
16165+
16166+ /* Zero the whole thing out */
16167+ memset(&exchange_state->req_state, 0, sizeof(packet_require_state_t));
16168+
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);
16173+
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--;
16181+ }
16182+
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",
16187+ 0);
16188+ ret = -1;
16189+ goto clean_exit;
16190+ }
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);
16197+ } else {
16198+ exchange_state->e_packet[5] = 0;
16199+ _libssh2_bn_to_bin(exchange_state->e,
16200+ exchange_state->e_packet + 6);
16201+ }
16202+
16203+ _libssh2_debug(session, LIBSSH2_DBG_KEX, "Sending KEX packet %d",
16204+ (int) packet_type_init);
16205+ exchange_state->state = libssh2_NB_state_created;
16206+ }
16207+
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;
16213+ } else if (rc) {
16214+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
16215+ "Unable to send KEX init message", 0);
16216+ ret = -1;
16217+ goto clean_exit;
16218+ }
16219+ exchange_state->state = libssh2_NB_state_sent;
16220+ }
16221+
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 */
16227+ int burn_type;
16228+
16229+ _libssh2_debug(session, LIBSSH2_DBG_KEX,
16230+ "Waiting for badly guessed KEX packet (to be ignored)");
16231+ burn_type =
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 */
16237+ ret = -1;
16238+ goto clean_exit;
16239+ }
16240+ session->burn_optimistic_kexinit = 0;
16241+
16242+ _libssh2_debug(session, LIBSSH2_DBG_KEX,
16243+ "Burnt packet of type: %02x",
16244+ (unsigned int) burn_type);
16245+ }
16246+
16247+ exchange_state->state = libssh2_NB_state_sent1;
16248+ }
16249+
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;
16258+ }
16259+ if (rc) {
16260+ libssh2_error(session, LIBSSH2_ERROR_TIMEOUT,
16261+ "Timed out waiting for KEX reply", 0);
16262+ ret = -1;
16263+ goto clean_exit;
16264+ }
16265+
16266+ /* Parse KEXDH_REPLY */
16267+ exchange_state->s = exchange_state->s_packet + 1;
16268+
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",
16276+ 0);
16277+ ret = -1;
16278+ goto clean_exit;
16279+ }
16280+ memcpy(session->server_hostkey, exchange_state->s,
16281+ session->server_hostkey_len);
16282+ exchange_state->s += session->server_hostkey_len;
16283+
16284+#if LIBSSH2_MD5
16285+ {
16286+ libssh2_md5_ctx fingerprint_ctx;
16287+
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);
16292+ }
16293+#ifdef LIBSSH2DEBUG
16294+ {
16295+ char fingerprint[50], *fprint = fingerprint;
16296+ int i;
16297+ for(i = 0; i < 16; i++, fprint += 3) {
16298+ snprintf(fprint, 4, "%02x:", session->server_hostkey_md5[i]);
16299+ }
16300+ *(--fprint) = '\0';
16301+ _libssh2_debug(session, LIBSSH2_DBG_KEX,
16302+ "Server's MD5 Fingerprint: %s", fingerprint);
16303+ }
16304+#endif /* LIBSSH2DEBUG */
16305+#endif /* ! LIBSSH2_MD5 */
16306+
16307+ {
16308+ libssh2_sha1_ctx fingerprint_ctx;
16309+
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);
16314+ }
16315+#ifdef LIBSSH2DEBUG
16316+ {
16317+ char fingerprint[64], *fprint = fingerprint;
16318+ int i;
16319+
16320+ for(i = 0; i < 20; i++, fprint += 3) {
16321+ snprintf(fprint, 4, "%02x:", session->server_hostkey_sha1[i]);
16322+ }
16323+ *(--fprint) = '\0';
16324+ _libssh2_debug(session, LIBSSH2_DBG_KEX,
16325+ "Server's SHA1 Fingerprint: %s", fingerprint);
16326+ }
16327+#endif /* LIBSSH2DEBUG */
16328+
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);
16334+ ret = -1;
16335+ goto clean_exit;
16336+ }
16337+
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);
16344+
16345+ exchange_state->h_sig_len = libssh2_ntohu32(exchange_state->s);
16346+ exchange_state->s += 4;
16347+ exchange_state->h_sig = exchange_state->s;
16348+
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--;
16356+ }
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);
16362+ ret = -1;
16363+ goto clean_exit;
16364+ }
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);
16369+ } else {
16370+ exchange_state->k_value[4] = 0;
16371+ _libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 5);
16372+ }
16373+
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);
16383+ } else {
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);
16391+ }
16392+
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));
16400+
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);
16408+
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);
16416+
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);
16424+
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);
16436+#else
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);
16441+#endif
16442+ }
16443+
16444+ if (midhash) {
16445+ libssh2_sha1_update(exchange_state->exchange_hash, midhash,
16446+ midhash_len);
16447+ }
16448+
16449+ libssh2_sha1_update(exchange_state->exchange_hash,
16450+ exchange_state->e_packet + 1,
16451+ exchange_state->e_packet_len - 1);
16452+
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);
16460+
16461+ libssh2_sha1_update(exchange_state->exchange_hash,
16462+ exchange_state->k_value,
16463+ exchange_state->k_value_len);
16464+
16465+ libssh2_sha1_final(exchange_state->exchange_hash,
16466+ exchange_state->h_sig_comp);
16467+
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);
16474+ ret = -1;
16475+ goto clean_exit;
16476+ }
16477+
16478+ _libssh2_debug(session, LIBSSH2_DBG_KEX, "Sending NEWKEYS message");
16479+ exchange_state->c = SSH_MSG_NEWKEYS;
16480+
16481+ exchange_state->state = libssh2_NB_state_sent2;
16482+ }
16483+
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;
16488+ } else if (rc) {
16489+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
16490+ "Unable to send NEWKEYS message", 0);
16491+ ret = -1;
16492+ goto clean_exit;
16493+ }
16494+
16495+ exchange_state->state = libssh2_NB_state_sent3;
16496+ }
16497+
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;
16505+ } else if (rc) {
16506+ libssh2_error(session, LIBSSH2_ERROR_TIMEOUT,
16507+ "Timed out waiting for NEWKEYS", 0);
16508+ ret = -1;
16509+ goto clean_exit;
16510+ }
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");
16515+
16516+ /* This will actually end up being just packet_type(1)
16517+ for this packet type anyway */
16518+ LIBSSH2_FREE(session, exchange_state->tmp);
16519+
16520+ if (!session->session_id) {
16521+ session->session_id = LIBSSH2_ALLOC(session, SHA_DIGEST_LENGTH);
16522+ if (!session->session_id) {
16523+ ret = -1;
16524+ goto clean_exit;
16525+ }
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");
16530+ }
16531+
16532+ /* Cleanup any existing cipher */
16533+ if (session->local.crypt->dtor) {
16534+ session->local.crypt->dtor(session,
16535+ &session->local.crypt_abstract);
16536+ }
16537+
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;
16542+
16543+ LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(iv,
16544+ session->local.crypt->
16545+ iv_len, "A");
16546+ if (!iv) {
16547+ ret = -1;
16548+ goto clean_exit;
16549+ }
16550+ LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(secret,
16551+ session->local.crypt->
16552+ secret_len, "C");
16553+ if (!secret) {
16554+ LIBSSH2_FREE(session, iv);
16555+ ret = -1;
16556+ goto clean_exit;
16557+ }
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);
16563+ ret = -1;
16564+ goto clean_exit;
16565+ }
16566+
16567+ if (free_iv) {
16568+ memset(iv, 0, session->local.crypt->iv_len);
16569+ LIBSSH2_FREE(session, iv);
16570+ }
16571+
16572+ if (free_secret) {
16573+ memset(secret, 0, session->local.crypt->secret_len);
16574+ LIBSSH2_FREE(session, secret);
16575+ }
16576+ }
16577+ _libssh2_debug(session, LIBSSH2_DBG_KEX,
16578+ "Client to Server IV and Key calculated");
16579+
16580+ if (session->remote.crypt->dtor) {
16581+ /* Cleanup any existing cipher */
16582+ session->remote.crypt->dtor(session,
16583+ &session->remote.crypt_abstract);
16584+ }
16585+
16586+ if (session->remote.crypt->init) {
16587+ unsigned char *iv = NULL, *secret = NULL;
16588+ int free_iv = 0, free_secret = 0;
16589+
16590+ LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(iv,
16591+ session->remote.crypt->
16592+ iv_len, "B");
16593+ if (!iv) {
16594+ ret = -1;
16595+ goto clean_exit;
16596+ }
16597+ LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(secret,
16598+ session->remote.crypt->
16599+ secret_len, "D");
16600+ if (!secret) {
16601+ LIBSSH2_FREE(session, iv);
16602+ ret = -1;
16603+ goto clean_exit;
16604+ }
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);
16610+ ret = -1;
16611+ goto clean_exit;
16612+ }
16613+
16614+ if (free_iv) {
16615+ memset(iv, 0, session->remote.crypt->iv_len);
16616+ LIBSSH2_FREE(session, iv);
16617+ }
16618+
16619+ if (free_secret) {
16620+ memset(secret, 0, session->remote.crypt->secret_len);
16621+ LIBSSH2_FREE(session, secret);
16622+ }
16623+ }
16624+ _libssh2_debug(session, LIBSSH2_DBG_KEX,
16625+ "Server to Client IV and Key calculated");
16626+
16627+ if (session->local.mac->dtor) {
16628+ session->local.mac->dtor(session, &session->local.mac_abstract);
16629+ }
16630+
16631+ if (session->local.mac->init) {
16632+ unsigned char *key = NULL;
16633+ int free_key = 0;
16634+
16635+ LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(key,
16636+ session->local.mac->
16637+ key_len, "E");
16638+ if (!key) {
16639+ ret = -1;
16640+ goto clean_exit;
16641+ }
16642+ session->local.mac->init(session, key, &free_key,
16643+ &session->local.mac_abstract);
16644+
16645+ if (free_key) {
16646+ memset(key, 0, session->local.mac->key_len);
16647+ LIBSSH2_FREE(session, key);
16648+ }
16649+ }
16650+ _libssh2_debug(session, LIBSSH2_DBG_KEX,
16651+ "Client to Server HMAC Key calculated");
16652+
16653+ if (session->remote.mac->dtor) {
16654+ session->remote.mac->dtor(session, &session->remote.mac_abstract);
16655+ }
16656+
16657+ if (session->remote.mac->init) {
16658+ unsigned char *key = NULL;
16659+ int free_key = 0;
16660+
16661+ LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(key,
16662+ session->remote.mac->
16663+ key_len, "F");
16664+ if (!key) {
16665+ ret = -1;
16666+ goto clean_exit;
16667+ }
16668+ session->remote.mac->init(session, key, &free_key,
16669+ &session->remote.mac_abstract);
16670+
16671+ if (free_key) {
16672+ memset(key, 0, session->remote.mac->key_len);
16673+ LIBSSH2_FREE(session, key);
16674+ }
16675+ }
16676+ _libssh2_debug(session, LIBSSH2_DBG_KEX,
16677+ "Server to Client HMAC Key calculated");
16678+ }
16679+
16680+ clean_exit:
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;
16691+
16692+ if (exchange_state->e_packet) {
16693+ LIBSSH2_FREE(session, exchange_state->e_packet);
16694+ exchange_state->e_packet = NULL;
16695+ }
16696+
16697+ if (exchange_state->s_packet) {
16698+ LIBSSH2_FREE(session, exchange_state->s_packet);
16699+ exchange_state->s_packet = NULL;
16700+ }
16701+
16702+ if (exchange_state->k_value) {
16703+ LIBSSH2_FREE(session, exchange_state->k_value);
16704+ exchange_state->k_value = NULL;
16705+ }
16706+
16707+ if (session->server_hostkey) {
16708+ LIBSSH2_FREE(session, session->server_hostkey);
16709+ session->server_hostkey = NULL;
16710+ }
16711+
16712+ exchange_state->state = libssh2_NB_state_idle;
16713+
16714+ return ret;
16715+}
16716+
16717+/* }}} */
16718+
16719+/* {{{ libssh2_kex_method_diffie_hellman_group1_sha1_key_exchange
16720+ * Diffie-Hellman Group1 (Actually Group2) Key Exchange using SHA1
16721+ */
16722+static int
16723+libssh2_kex_method_diffie_hellman_group1_sha1_key_exchange(LIBSSH2_SESSION *
16724+ session,
16725+ key_exchange_state_low_t
16726+ * key_state)
16727+{
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
16745+ };
16746+
16747+ int ret;
16748+
16749+ if (key_state->state == libssh2_NB_state_idle) {
16750+ /* g == 2 */
16751+ key_state->p = _libssh2_bn_init(); /* SSH2 defined value (p_value) */
16752+ key_state->g = _libssh2_bn_init(); /* SSH2 defined value (2) */
16753+
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);
16757+
16758+ _libssh2_debug(session, LIBSSH2_DBG_KEX,
16759+ "Initiating Diffie-Hellman Group1 Key Exchange");
16760+
16761+ key_state->state = libssh2_NB_state_created;
16762+ }
16763+
16764+ ret =
16765+ libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(session,
16766+ key_state->
16767+ g,
16768+ key_state->
16769+ p, 128,
16770+ SSH_MSG_KEXDH_INIT,
16771+ SSH_MSG_KEXDH_REPLY,
16772+ NULL, 0,
16773+ &key_state->
16774+ exchange_state);
16775+ if (ret == PACKET_EAGAIN) {
16776+ return PACKET_EAGAIN;
16777+ }
16778+
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;
16784+
16785+ return ret;
16786+}
16787+
16788+/* }}} */
16789+
16790+/* {{{ libssh2_kex_method_diffie_hellman_group14_sha1_key_exchange
16791+ * Diffie-Hellman Group14 Key Exchange using SHA1
16792+ */
16793+static int
16794+libssh2_kex_method_diffie_hellman_group14_sha1_key_exchange(LIBSSH2_SESSION *
16795+ session,
16796+ key_exchange_state_low_t
16797+ * key_state)
16798+{
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
16832+ };
16833+ int ret;
16834+
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) */
16838+
16839+ /* g == 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);
16843+
16844+ _libssh2_debug(session, LIBSSH2_DBG_KEX,
16845+ "Initiating Diffie-Hellman Group14 Key Exchange");
16846+
16847+ key_state->state = libssh2_NB_state_created;
16848+ }
16849+ ret =
16850+ libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(session,
16851+ key_state->
16852+ g,
16853+ key_state->
16854+ p, 256,
16855+ SSH_MSG_KEXDH_INIT,
16856+ SSH_MSG_KEXDH_REPLY,
16857+ NULL, 0,
16858+ &key_state->
16859+ exchange_state);
16860+ if (ret == PACKET_EAGAIN) {
16861+ return PACKET_EAGAIN;
16862+ }
16863+
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;
16869+
16870+ return ret;
16871+}
16872+
16873+/* }}} */
16874+
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
16878+ */
16879+static int
16880+ libssh2_kex_method_diffie_hellman_group_exchange_sha1_key_exchange
16881+ (LIBSSH2_SESSION * session, key_exchange_state_low_t * key_state)
16882+{
16883+ unsigned char *s;
16884+ unsigned long p_len, g_len;
16885+ int ret = 0;
16886+ int rc;
16887+
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)");
16900+#else
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)");
16906+#endif
16907+
16908+ key_state->state = libssh2_NB_state_created;
16909+ }
16910+
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;
16916+ } else if (rc) {
16917+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
16918+ "Unable to send Group Exchange Request", 0);
16919+ ret = -1;
16920+ goto dh_gex_clean_exit;
16921+ }
16922+
16923+ key_state->state = libssh2_NB_state_sent;
16924+ }
16925+
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;
16932+ } else if (rc) {
16933+ libssh2_error(session, LIBSSH2_ERROR_TIMEOUT,
16934+ "Timeout waiting for GEX_GROUP reply", 0);
16935+ ret = -1;
16936+ goto dh_gex_clean_exit;
16937+ }
16938+
16939+ key_state->state = libssh2_NB_state_sent1;
16940+ }
16941+
16942+ if (key_state->state == libssh2_NB_state_sent1) {
16943+ s = key_state->data + 1;
16944+ p_len = libssh2_ntohu32(s);
16945+ s += 4;
16946+ _libssh2_bn_from_bin(key_state->p, p_len, s);
16947+ s += p_len;
16948+
16949+ g_len = libssh2_ntohu32(s);
16950+ s += 4;
16951+ _libssh2_bn_from_bin(key_state->g, g_len, s);
16952+ s += g_len;
16953+
16954+ ret =
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;
16962+ }
16963+
16964+ LIBSSH2_FREE(session, key_state->data);
16965+ }
16966+
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;
16973+
16974+ return ret;
16975+}
16976+
16977+/* }}} */
16978+
16979+#define LIBSSH2_KEX_METHOD_FLAG_REQ_ENC_HOSTKEY 0x0001
16980+#define LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY 0x0002
16981+
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,
16986+};
16987+
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,
16992+};
16993+
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,
16999+};
17000+
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,
17005+ NULL
17006+};
17007+
17008+typedef struct _LIBSSH2_COMMON_METHOD
17009+{
17010+ const char *name;
17011+} LIBSSH2_COMMON_METHOD;
17012+
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.
17017+ */
17018+static size_t
17019+libssh2_kex_method_strlen(LIBSSH2_COMMON_METHOD ** method)
17020+{
17021+ size_t len = 0;
17022+
17023+ if (!method || !*method) {
17024+ return 0;
17025+ }
17026+
17027+ while (*method && (*method)->name) {
17028+ len += strlen((*method)->name) + 1;
17029+ method++;
17030+ }
17031+
17032+ return len - 1;
17033+}
17034+
17035+/* }}} */
17036+
17037+/* {{{ libssh2_kex_method_list
17038+ * Generate formatted preference list in buf
17039+ */
17040+static size_t
17041+libssh2_kex_method_list(unsigned char *buf, size_t list_strlen,
17042+ LIBSSH2_COMMON_METHOD ** method)
17043+{
17044+ libssh2_htonu32(buf, list_strlen);
17045+ buf += 4;
17046+
17047+ if (!method || !*method) {
17048+ return 4;
17049+ }
17050+
17051+ while (*method && (*method)->name) {
17052+ int mlen = strlen((*method)->name);
17053+ memcpy(buf, (*method)->name, mlen);
17054+ buf += mlen;
17055+ *(buf++) = ',';
17056+ method++;
17057+ }
17058+
17059+ return list_strlen + 4;
17060+}
17061+
17062+/* }}} */
17063+
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) \
17066+ if (prefvar) { \
17067+ libssh2_htonu32((buf), (prefvarlen)); \
17068+ buf += 4; \
17069+ memcpy((buf), (prefvar), (prefvarlen)); \
17070+ buf += (prefvarlen); \
17071+ } else { \
17072+ buf += libssh2_kex_method_list((buf), (prefvarlen), (LIBSSH2_COMMON_METHOD**)(defaultvar)); \
17073+ }
17074+
17075+/* {{{ libssh2_kexinit
17076+ * Send SSH_MSG_KEXINIT packet
17077+ */
17078+static int
17079+libssh2_kexinit(LIBSSH2_SESSION * session)
17080+{
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;
17090+ int rc;
17091+
17092+ if (session->kexinit_state == libssh2_NB_state_idle) {
17093+ kex_len =
17094+ LIBSSH2_METHOD_PREFS_LEN(session->kex_prefs, libssh2_kex_methods);
17095+ hostkey_len =
17096+ LIBSSH2_METHOD_PREFS_LEN(session->hostkey_prefs,
17097+ libssh2_hostkey_methods());
17098+ crypt_cs_len =
17099+ LIBSSH2_METHOD_PREFS_LEN(session->local.crypt_prefs,
17100+ libssh2_crypt_methods());
17101+ crypt_sc_len =
17102+ LIBSSH2_METHOD_PREFS_LEN(session->remote.crypt_prefs,
17103+ libssh2_crypt_methods());
17104+ mac_cs_len =
17105+ LIBSSH2_METHOD_PREFS_LEN(session->local.mac_prefs,
17106+ libssh2_mac_methods());
17107+ mac_sc_len =
17108+ LIBSSH2_METHOD_PREFS_LEN(session->remote.mac_prefs,
17109+ libssh2_mac_methods());
17110+ comp_cs_len =
17111+ LIBSSH2_METHOD_PREFS_LEN(session->local.comp_prefs,
17112+ libssh2_comp_methods());
17113+ comp_sc_len =
17114+ LIBSSH2_METHOD_PREFS_LEN(session->remote.comp_prefs,
17115+ libssh2_comp_methods());
17116+ lang_cs_len =
17117+ LIBSSH2_METHOD_PREFS_LEN(session->local.lang_prefs, NULL);
17118+ lang_sc_len =
17119+ LIBSSH2_METHOD_PREFS_LEN(session->remote.lang_prefs, NULL);
17120+
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;
17124+
17125+ s = data = LIBSSH2_ALLOC(session, data_len);
17126+ if (!data) {
17127+ libssh2_error(session, LIBSSH2_ERROR_ALLOC,
17128+ "Unable to allocate memory", 0);
17129+ return -1;
17130+ }
17131+
17132+ *(s++) = SSH_MSG_KEXINIT;
17133+
17134+ libssh2_random(s, 16);
17135+ s += 16;
17136+
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,
17157+ NULL);
17158+ LIBSSH2_METHOD_PREFS_STR(s, lang_sc_len, session->remote.lang_prefs,
17159+ NULL);
17160+
17161+ /* No optimistic KEX packet follows */
17162+ /* Deal with optimistic packets
17163+ * session->flags |= KEXINIT_OPTIMISTIC
17164+ * session->flags |= KEXINIT_METHODSMATCH
17165+ */
17166+ *(s++) = 0;
17167+
17168+ /* Reserved == 0 */
17169+ *(s++) = 0;
17170+ *(s++) = 0;
17171+ *(s++) = 0;
17172+ *(s++) = 0;
17173+
17174+#ifdef LIBSSH2DEBUG
17175+ {
17176+ /* Funnily enough, they'll all "appear" to be '\0' terminated */
17177+ unsigned char *p = data + 21; /* type(1) + cookie(16) + len(4) */
17178+
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;
17199+ }
17200+#endif /* LIBSSH2DEBUG */
17201+
17202+ session->kexinit_state = libssh2_NB_state_created;
17203+ } else {
17204+ data = session->kexinit_data;
17205+ data_len = session->kexinit_data_len;
17206+ }
17207+
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;
17212+ } else if (rc) {
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;
17217+ return -1;
17218+ }
17219+
17220+ if (session->local.kexinit) {
17221+ LIBSSH2_FREE(session, session->local.kexinit);
17222+ }
17223+
17224+ session->local.kexinit = data;
17225+ session->local.kexinit_len = data_len;
17226+
17227+ session->kexinit_state = libssh2_NB_state_idle;
17228+
17229+ return 0;
17230+}
17231+
17232+/* }}} */
17233+
17234+/* {{{ libssh2_kex_agree_instr
17235+ * Kex specific variant of strstr()
17236+ * Needle must be preceed by BOL or ',', and followed by ',' or EOL
17237+ */
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)
17241+{
17242+ unsigned char *s;
17243+
17244+ /* Haystack too short to bother trying */
17245+ if (haystack_len < needle_len) {
17246+ return NULL;
17247+ }
17248+
17249+ /* Needle at start of haystack */
17250+ if ((strncmp((char *) haystack, (char *) needle, needle_len) == 0) &&
17251+ (needle_len == haystack_len || haystack[needle_len] == ',')) {
17252+ return haystack;
17253+ }
17254+
17255+ s = haystack;
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)) {
17260+ s++;
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] == ',')) {
17265+ return s;
17266+ }
17267+ }
17268+
17269+ return NULL;
17270+}
17271+
17272+/* }}} */
17273+
17274+/* {{{ libssh2_get_method_by_name
17275+ */
17276+static const LIBSSH2_COMMON_METHOD *
17277+libssh2_get_method_by_name(const char *name, int name_len,
17278+ const LIBSSH2_COMMON_METHOD ** methodlist)
17279+{
17280+ while (*methodlist) {
17281+ if ((strlen((*methodlist)->name) == name_len) &&
17282+ (strncmp((*methodlist)->name, name, name_len) == 0)) {
17283+ return *methodlist;
17284+ }
17285+ methodlist++;
17286+ }
17287+ return NULL;
17288+}
17289+
17290+/* }}} */
17291+
17292+/* {{{ libssh2_kex_agree_hostkey
17293+ * Agree on a Hostkey which works with this kex
17294+ */
17295+static int
17296+libssh2_kex_agree_hostkey(LIBSSH2_SESSION * session, unsigned long kex_flags,
17297+ unsigned char *hostkey, unsigned long hostkey_len)
17298+{
17299+ const LIBSSH2_HOSTKEY_METHOD **hostkeyp = libssh2_hostkey_methods();
17300+ unsigned char *s;
17301+
17302+ if (session->hostkey_prefs) {
17303+ s = (unsigned char *) session->hostkey_prefs;
17304+
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 **)
17313+ hostkeyp);
17314+
17315+ if (!method) {
17316+ /* Invalid method -- Should never be reached */
17317+ return -1;
17318+ }
17319+
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;
17328+ return 0;
17329+ }
17330+ }
17331+ }
17332+
17333+ s = p ? p + 1 : NULL;
17334+ }
17335+ return -1;
17336+ }
17337+
17338+ while (hostkeyp && (*hostkeyp)->name) {
17339+ s = libssh2_kex_agree_instr(hostkey, hostkey_len,
17340+ (unsigned char *) (*hostkeyp)->name,
17341+ strlen((*hostkeyp)->name));
17342+ if (s) {
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;
17351+ return 0;
17352+ }
17353+ }
17354+ }
17355+ hostkeyp++;
17356+ }
17357+
17358+ return -1;
17359+}
17360+
17361+/* }}} */
17362+
17363+/* {{{ libssh2_kex_agree_kex_hostkey
17364+ * Agree on a Key Exchange method and a hostkey encoding type
17365+ */
17366+static int
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)
17370+{
17371+ const LIBSSH2_KEX_METHOD **kexp = libssh2_kex_methods;
17372+ unsigned char *s;
17373+
17374+ if (session->kex_prefs) {
17375+ s = (unsigned char *) session->kex_prefs;
17376+
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 **)
17384+ kexp);
17385+
17386+ if (!method) {
17387+ /* Invalid method -- Should never be reached */
17388+ return -1;
17389+ }
17390+
17391+ /* We've agreed on a key exchange method,
17392+ * Can we agree on a hostkey that works with this kex?
17393+ */
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;
17402+ }
17403+ return 0;
17404+ }
17405+ }
17406+
17407+ s = p ? p + 1 : NULL;
17408+ }
17409+ return -1;
17410+ }
17411+
17412+ while (*kexp && (*kexp)->name) {
17413+ s = libssh2_kex_agree_instr(kex, kex_len,
17414+ (unsigned char *) (*kexp)->name,
17415+ strlen((*kexp)->name));
17416+ if (s) {
17417+ /* We've agreed on a key exchange method,
17418+ * Can we agree on a hostkey that works with this kex?
17419+ */
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;
17428+ }
17429+ return 0;
17430+ }
17431+ }
17432+ kexp++;
17433+ }
17434+ return -1;
17435+}
17436+
17437+/* }}} */
17438+
17439+/* {{{ libssh2_kex_agree_crypt
17440+ * Agree on a cipher algo
17441+ */
17442+static int
17443+libssh2_kex_agree_crypt(LIBSSH2_SESSION * session,
17444+ libssh2_endpoint_data * endpoint, unsigned char *crypt,
17445+ unsigned long crypt_len)
17446+{
17447+ const LIBSSH2_CRYPT_METHOD **cryptp = libssh2_crypt_methods();
17448+ unsigned char *s;
17449+
17450+ (void) session;
17451+
17452+ if (endpoint->crypt_prefs) {
17453+ s = (unsigned char *) endpoint->crypt_prefs;
17454+
17455+ while (s && *s) {
17456+ unsigned char *p = (unsigned char *) strchr((char *) s, ',');
17457+ int method_len = (p ? (p - s) : strlen((char *) s));
17458+
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 **)
17464+ cryptp);
17465+
17466+ if (!method) {
17467+ /* Invalid method -- Should never be reached */
17468+ return -1;
17469+ }
17470+
17471+ endpoint->crypt = method;
17472+ return 0;
17473+ }
17474+
17475+ s = p ? p + 1 : NULL;
17476+ }
17477+ return -1;
17478+ }
17479+
17480+ while (*cryptp && (*cryptp)->name) {
17481+ s = libssh2_kex_agree_instr(crypt, crypt_len,
17482+ (unsigned char *) (*cryptp)->name,
17483+ strlen((*cryptp)->name));
17484+ if (s) {
17485+ endpoint->crypt = *cryptp;
17486+ return 0;
17487+ }
17488+ cryptp++;
17489+ }
17490+
17491+ return -1;
17492+}
17493+
17494+/* }}} */
17495+
17496+/* {{{ libssh2_kex_agree_mac
17497+ * Agree on a message authentication hash
17498+ */
17499+static int
17500+libssh2_kex_agree_mac(LIBSSH2_SESSION * session,
17501+ libssh2_endpoint_data * endpoint, unsigned char *mac,
17502+ unsigned long mac_len)
17503+{
17504+ const LIBSSH2_MAC_METHOD **macp = libssh2_mac_methods();
17505+ unsigned char *s;
17506+ (void) session;
17507+
17508+ if (endpoint->mac_prefs) {
17509+ s = (unsigned char *) endpoint->mac_prefs;
17510+
17511+ while (s && *s) {
17512+ unsigned char *p = (unsigned char *) strchr((char *) s, ',');
17513+ int method_len = (p ? (p - s) : strlen((char *) s));
17514+
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 **)
17519+ macp);
17520+
17521+ if (!method) {
17522+ /* Invalid method -- Should never be reached */
17523+ return -1;
17524+ }
17525+
17526+ endpoint->mac = method;
17527+ return 0;
17528+ }
17529+
17530+ s = p ? p + 1 : NULL;
17531+ }
17532+ return -1;
17533+ }
17534+
17535+ while (*macp && (*macp)->name) {
17536+ s = libssh2_kex_agree_instr(mac, mac_len,
17537+ (unsigned char *) (*macp)->name,
17538+ strlen((*macp)->name));
17539+ if (s) {
17540+ endpoint->mac = *macp;
17541+ return 0;
17542+ }
17543+ macp++;
17544+ }
17545+
17546+ return -1;
17547+}
17548+
17549+/* }}} */
17550+
17551+/* {{{ libssh2_kex_agree_comp
17552+ * Agree on a compression scheme
17553+ */
17554+static int
17555+libssh2_kex_agree_comp(LIBSSH2_SESSION * session,
17556+ libssh2_endpoint_data * endpoint, unsigned char *comp,
17557+ unsigned long comp_len)
17558+{
17559+ const LIBSSH2_COMP_METHOD **compp = libssh2_comp_methods();
17560+ unsigned char *s;
17561+ (void) session;
17562+
17563+ if (endpoint->comp_prefs) {
17564+ s = (unsigned char *) endpoint->comp_prefs;
17565+
17566+ while (s && *s) {
17567+ unsigned char *p = (unsigned char *) strchr((char *) s, ',');
17568+ int method_len = (p ? (p - s) : strlen((char *) s));
17569+
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 **)
17575+ compp);
17576+
17577+ if (!method) {
17578+ /* Invalid method -- Should never be reached */
17579+ return -1;
17580+ }
17581+
17582+ endpoint->comp = method;
17583+ return 0;
17584+ }
17585+
17586+ s = p ? p + 1 : NULL;
17587+ }
17588+ return -1;
17589+ }
17590+
17591+ while (*compp && (*compp)->name) {
17592+ s = libssh2_kex_agree_instr(comp, comp_len,
17593+ (unsigned char *) (*compp)->name,
17594+ strlen((*compp)->name));
17595+ if (s) {
17596+ endpoint->comp = *compp;
17597+ return 0;
17598+ }
17599+ compp++;
17600+ }
17601+
17602+ return -1;
17603+}
17604+
17605+/* }}} */
17606+
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"
17609+ */
17610+
17611+/* {{{ libssh2_kex_agree_methods
17612+ * Decide which specific method to use of the methods offered by each party
17613+ */
17614+static int
17615+libssh2_kex_agree_methods(LIBSSH2_SESSION * session, unsigned char *data,
17616+ unsigned data_len)
17617+{
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;
17623+
17624+ /* Skip packet_type, we know it already */
17625+ s++;
17626+
17627+ /* Skip cookie, don't worry, it's preserved in the kexinit field */
17628+ s += 16;
17629+
17630+ /* Locate each string */
17631+ kex_len = libssh2_ntohu32(s);
17632+ kex = s + 4;
17633+ s += 4 + kex_len;
17634+ hostkey_len = libssh2_ntohu32(s);
17635+ hostkey = s + 4;
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);
17644+ mac_cs = s + 4;
17645+ s += 4 + mac_cs_len;
17646+ mac_sc_len = libssh2_ntohu32(s);
17647+ mac_sc = s + 4;
17648+ s += 4 + mac_sc_len;
17649+ comp_cs_len = libssh2_ntohu32(s);
17650+ comp_cs = s + 4;
17651+ s += 4 + comp_cs_len;
17652+ comp_sc_len = libssh2_ntohu32(s);
17653+ comp_sc = s + 4;
17654+ s += 4 + comp_sc_len;
17655+ lang_cs_len = libssh2_ntohu32(s);
17656+ lang_cs = s + 4;
17657+ s += 4 + lang_cs_len;
17658+ lang_sc_len = libssh2_ntohu32(s);
17659+ lang_sc = s + 4;
17660+ s += 4 + lang_sc_len;
17661+
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) */
17667+
17668+ if (data_len < (unsigned) (s - data))
17669+ return -1; /* short packet */
17670+
17671+ if (libssh2_kex_agree_kex_hostkey
17672+ (session, kex, kex_len, hostkey, hostkey_len)) {
17673+ return -1;
17674+ }
17675+
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,
17679+ crypt_sc_len)) {
17680+ return -1;
17681+ }
17682+
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)) {
17685+ return -1;
17686+ }
17687+
17688+ if (libssh2_kex_agree_comp(session, &session->local, comp_cs, comp_cs_len)
17689+ || libssh2_kex_agree_comp(session, &session->remote, comp_sc,
17690+ comp_sc_len)) {
17691+ return -1;
17692+ }
17693+
17694+ if (libssh2_kex_agree_lang(session, &session->local, lang_cs, lang_cs_len)
17695+ || libssh2_kex_agree_lang(session, &session->remote, lang_sc,
17696+ lang_sc_len)) {
17697+ return -1;
17698+ }
17699+
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 */
17718+
17719+ /* Initialize compression layer */
17720+ if (session->local.comp && session->local.comp->init &&
17721+ session->local.comp->init(session, 1, &session->local.comp_abstract)) {
17722+ return -1;
17723+ }
17724+
17725+ if (session->remote.comp && session->remote.comp->init &&
17726+ session->remote.comp->init(session, 0,
17727+ &session->remote.comp_abstract)) {
17728+ return -1;
17729+ }
17730+
17731+ return 0;
17732+}
17733+
17734+/* }}} */
17735+
17736+/* {{{ libssh2_kex_exchange
17737+ * Exchange keys
17738+ * Returns 0 on success, non-zero on failure
17739+ */
17740+int
17741+libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange,
17742+ key_exchange_state_t * key_state)
17743+{
17744+ int rc = 0;
17745+ int retcode;
17746+
17747+ session->state |= LIBSSH2_STATE_KEX_ACTIVE;
17748+
17749+ if (key_state->state == libssh2_NB_state_idle) {
17750+ /* Prevent loop in packet_add() */
17751+ session->state |= LIBSSH2_STATE_EXCHANGING_KEYS;
17752+
17753+ if (reexchange) {
17754+ session->kex = NULL;
17755+
17756+ if (session->hostkey && session->hostkey->dtor) {
17757+ session->hostkey->dtor(session,
17758+ &session->server_hostkey_abstract);
17759+ }
17760+ session->hostkey = NULL;
17761+ }
17762+
17763+ key_state->state = libssh2_NB_state_created;
17764+ }
17765+
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;
17771+
17772+ session->local.kexinit = NULL;
17773+
17774+ key_state->state = libssh2_NB_state_sent;
17775+ }
17776+
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;
17788+ return -1;
17789+ }
17790+
17791+ key_state->state = libssh2_NB_state_sent1;
17792+ }
17793+
17794+ if (key_state->state == libssh2_NB_state_sent1) {
17795+ retcode =
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);
17806+ }
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;
17812+ return -1;
17813+ }
17814+
17815+ if (session->remote.kexinit) {
17816+ LIBSSH2_FREE(session, session->remote.kexinit);
17817+ }
17818+ session->remote.kexinit = key_state->data;
17819+ session->remote.kexinit_len = key_state->data_len;
17820+
17821+ if (libssh2_kex_agree_methods
17822+ (session, key_state->data, key_state->data_len)) {
17823+ rc = -1;
17824+ }
17825+
17826+ key_state->state = libssh2_NB_state_sent2;
17827+ }
17828+ } else {
17829+ key_state->state = libssh2_NB_state_sent2;
17830+ }
17831+
17832+ if (rc == 0) {
17833+ if (key_state->state == libssh2_NB_state_sent2) {
17834+ retcode =
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);
17843+ rc = -1;
17844+ }
17845+ }
17846+ }
17847+
17848+ /* Done with kexinit buffers */
17849+ if (session->local.kexinit) {
17850+ LIBSSH2_FREE(session, session->local.kexinit);
17851+ session->local.kexinit = NULL;
17852+ }
17853+ if (session->remote.kexinit) {
17854+ LIBSSH2_FREE(session, session->remote.kexinit);
17855+ session->remote.kexinit = NULL;
17856+ }
17857+
17858+ session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
17859+ session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS;
17860+
17861+ key_state->state = libssh2_NB_state_idle;
17862+
17863+ return rc;
17864+}
17865+
17866+/* }}} */
17867+
17868+/* {{{ libssh2_session_method_pref
17869+ * Set preferred method
17870+ */
17871+LIBSSH2_API int
17872+libssh2_session_method_pref(LIBSSH2_SESSION * session, int method_type,
17873+ const char *prefs)
17874+{
17875+ char **prefvar, *s, *newprefs;
17876+ int prefs_len = strlen(prefs);
17877+ const LIBSSH2_COMMON_METHOD **mlist;
17878+
17879+ switch (method_type) {
17880+ case LIBSSH2_METHOD_KEX:
17881+ prefvar = &session->kex_prefs;
17882+ mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_kex_methods;
17883+ break;
17884+
17885+ case LIBSSH2_METHOD_HOSTKEY:
17886+ prefvar = &session->hostkey_prefs;
17887+ mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_hostkey_methods();
17888+ break;
17889+
17890+ case LIBSSH2_METHOD_CRYPT_CS:
17891+ prefvar = &session->local.crypt_prefs;
17892+ mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_crypt_methods();
17893+ break;
17894+
17895+ case LIBSSH2_METHOD_CRYPT_SC:
17896+ prefvar = &session->remote.crypt_prefs;
17897+ mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_crypt_methods();
17898+ break;
17899+
17900+ case LIBSSH2_METHOD_MAC_CS:
17901+ prefvar = &session->local.mac_prefs;
17902+ mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_mac_methods();
17903+ break;
17904+
17905+ case LIBSSH2_METHOD_MAC_SC:
17906+ prefvar = &session->remote.mac_prefs;
17907+ mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_mac_methods();
17908+ break;
17909+
17910+ case LIBSSH2_METHOD_COMP_CS:
17911+ prefvar = &session->local.comp_prefs;
17912+ mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_comp_methods();
17913+ break;
17914+
17915+ case LIBSSH2_METHOD_COMP_SC:
17916+ prefvar = &session->remote.comp_prefs;
17917+ mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_comp_methods();
17918+ break;
17919+
17920+ case LIBSSH2_METHOD_LANG_CS:
17921+ prefvar = &session->local.lang_prefs;
17922+ mlist = NULL;
17923+ break;
17924+
17925+ case LIBSSH2_METHOD_LANG_SC:
17926+ prefvar = &session->remote.lang_prefs;
17927+ mlist = NULL;
17928+ break;
17929+
17930+ default:
17931+ libssh2_error(session, LIBSSH2_ERROR_INVAL,
17932+ "Invalid parameter specified for method_type", 0);
17933+ return -1;
17934+ }
17935+
17936+ s = newprefs = LIBSSH2_ALLOC(session, prefs_len + 1);
17937+ if (!newprefs) {
17938+ libssh2_error(session, LIBSSH2_ERROR_ALLOC,
17939+ "Error allocated space for method preferences", 0);
17940+ return -1;
17941+ }
17942+ memcpy(s, prefs, prefs_len + 1);
17943+
17944+ while (s && *s) {
17945+ char *p = strchr(s, ',');
17946+ int method_len = p ? (p - s) : (int) strlen(s);
17947+
17948+ if (!libssh2_get_method_by_name(s, method_len, mlist)) {
17949+ /* Strip out unsupported method */
17950+ if (p) {
17951+ memcpy(s, p + 1, strlen(s) - method_len);
17952+ } else {
17953+ if (s > newprefs) {
17954+ *(--s) = '\0';
17955+ } else {
17956+ *s = '\0';
17957+ }
17958+ }
17959+ }
17960+
17961+ s = p ? (p + 1) : NULL;
17962+ }
17963+
17964+ if (strlen(newprefs) == 0) {
17965+ libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
17966+ "The requested method(s) are not currently supported",
17967+ 0);
17968+ LIBSSH2_FREE(session, newprefs);
17969+ return -1;
17970+ }
17971+
17972+ if (*prefvar) {
17973+ LIBSSH2_FREE(session, *prefvar);
17974+ }
17975+ *prefvar = newprefs;
17976+
17977+ return 0;
17978+}
17979+
17980+/* }}} */
17981
17982Property changes on: libssh2/src/kex.c
17983___________________________________________________________________
17984Added: svn:mime-type
17985 + text/x-c
17986Added: svn:keywords
17987 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
17988Added: cvs2svn:cvs-rev
17989 + 1.3
17990Added: svn:eol-style
17991 + native
17992
17993Index: libssh2/src/openssl.h
17994===================================================================
17995--- libssh2/src/openssl.h (.../tags/RELEASE_0_11_0)
17996+++ libssh2/src/openssl.h (.../trunk)
17997@@ -0,0 +1,224 @@
17998+/* Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved.
17999+ * Author: Simon Josefsson
18000+ *
18001+ * Redistribution and use in source and binary forms,
18002+ * with or without modification, are permitted provided
18003+ * that the following conditions are met:
18004+ *
18005+ * Redistributions of source code must retain the above
18006+ * copyright notice, this list of conditions and the
18007+ * following disclaimer.
18008+ *
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.
18013+ *
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.
18018+ *
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.
18033+ */
18034+
18035+#include <openssl/opensslconf.h>
18036+#include <openssl/sha.h>
18037+#ifndef OPENSSL_NO_MD5
18038+#include <openssl/md5.h>
18039+#endif
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>
18045+
18046+#ifdef OPENSSL_NO_RSA
18047+# define LIBSSH2_RSA 0
18048+#else
18049+# define LIBSSH2_RSA 1
18050+#endif
18051+
18052+#ifdef OPENSSL_NO_DSA
18053+# define LIBSSH2_DSA 0
18054+#else
18055+# define LIBSSH2_DSA 1
18056+#endif
18057+
18058+#ifdef OPENSSL_NO_MD5
18059+# define LIBSSH2_MD5 0
18060+#else
18061+# define LIBSSH2_MD5 1
18062+#endif
18063+
18064+#ifdef OPENSSL_NO_RIPEMD
18065+# define LIBSSH2_HMAC_RIPEMD 0
18066+#else
18067+# define LIBSSH2_HMAC_RIPEMD 1
18068+#endif
18069+
18070+#if OPENSSL_VERSION_NUMBER >= 0x00907000L && !defined(OPENSSL_NO_AES)
18071+# define LIBSSH2_AES 1
18072+#else
18073+# define LIBSSH2_AES 0
18074+#endif
18075+
18076+#ifdef OPENSSL_NO_BLOWFISH
18077+# define LIBSSH2_BLOWFISH 0
18078+#else
18079+# define LIBSSH2_BLOWFISH 1
18080+#endif
18081+
18082+#ifdef OPENSSL_NO_RC4
18083+# define LIBSSH2_RC4 0
18084+#else
18085+# define LIBSSH2_RC4 1
18086+#endif
18087+
18088+#ifdef OPENSSL_NO_CAST
18089+# define LIBSSH2_CAST 0
18090+#else
18091+# define LIBSSH2_CAST 1
18092+#endif
18093+
18094+#ifdef OPENSSL_NO_DES
18095+# define LIBSSH2_3DES 0
18096+#else
18097+# define LIBSSH2_3DES 1
18098+#endif
18099+
18100+#define libssh2_random(buf, len) \
18101+ RAND_bytes ((buf), (len))
18102+
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)
18108+
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)
18114+
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)
18126+
18127+#define libssh2_crypto_init()
18128+
18129+#define libssh2_rsa_ctx RSA
18130+
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);
18160+
18161+#define _libssh2_rsa_free(rsactx) RSA_free(rsactx)
18162+
18163+#define libssh2_dsa_ctx DSA
18164+
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);
18184+
18185+#define _libssh2_dsa_free(dsactx) DSA_free(dsactx)
18186+
18187+#define _libssh2_cipher_type(name) const EVP_CIPHER *(*name)(void)
18188+#define _libssh2_cipher_ctx EVP_CIPHER_CTX
18189+
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
18197+
18198+int _libssh2_cipher_init(_libssh2_cipher_ctx * h,
18199+ _libssh2_cipher_type(algo),
18200+ unsigned char *iv,
18201+ unsigned char *secret, int encrypt);
18202+
18203+int _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx,
18204+ _libssh2_cipher_type(algo),
18205+ int encrypt, unsigned char *block);
18206+
18207+#define _libssh2_cipher_dtor(ctx) EVP_CIPHER_CTX_cleanup(ctx)
18208+
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)
18222
18223Property changes on: libssh2/src/openssl.h
18224___________________________________________________________________
18225Added: svn:mime-type
18226 + text/x-c
18227Added: svn:keywords
18228 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
18229Added: cvs2svn:cvs-rev
18230 + 1.1
18231Added: svn:eol-style
18232 + native
18233Added: svn:executable
18234 + *
18235
18236Index: libssh2/src/misc.c
18237===================================================================
18238--- libssh2/src/misc.c (.../tags/RELEASE_0_11_0)
18239+++ libssh2/src/misc.c (.../trunk)
18240@@ -0,0 +1,240 @@
18241+/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
18242+ * All rights reserved.
18243+ *
18244+ * Redistribution and use in source and binary forms,
18245+ * with or without modification, are permitted provided
18246+ * that the following conditions are met:
18247+ *
18248+ * Redistributions of source code must retain the above
18249+ * copyright notice, this list of conditions and the
18250+ * following disclaimer.
18251+ *
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.
18256+ *
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.
18261+ *
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.
18276+ */
18277+
18278+#include "libssh2_priv.h"
18279+#ifdef HAVE_UNISTD_H
18280+#include <unistd.h>
18281+#endif
18282+
18283+/* {{{ libssh2_ntohu32
18284+ */
18285+unsigned long
18286+libssh2_ntohu32(const unsigned char *buf)
18287+{
18288+ return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
18289+}
18290+
18291+/* }}} */
18292+
18293+/* {{{ libssh2_ntohu64
18294+ *
18295+ */
18296+libssh2_uint64_t
18297+libssh2_ntohu64(const unsigned char *buf)
18298+{
18299+ unsigned long msl, lsl;
18300+
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];
18303+
18304+ return ((libssh2_uint64_t)msl <<32) | lsl;
18305+}
18306+
18307+/* }}} */
18308+
18309+/* {{{ libssh2_htonu32
18310+ */
18311+void
18312+libssh2_htonu32(unsigned char *buf, unsigned long value)
18313+{
18314+ buf[0] = (value >> 24) & 0xFF;
18315+ buf[1] = (value >> 16) & 0xFF;
18316+ buf[2] = (value >> 8) & 0xFF;
18317+ buf[3] = value & 0xFF;
18318+}
18319+
18320+/* }}} */
18321+
18322+/* {{{ libssh2_htonu64
18323+ */
18324+void
18325+libssh2_htonu64(unsigned char *buf, libssh2_uint64_t value)
18326+{
18327+ unsigned long msl = ((libssh2_uint64_t)value >> 32);
18328+
18329+ buf[0] = (msl >> 24) & 0xFF;
18330+ buf[1] = (msl >> 16) & 0xFF;
18331+ buf[2] = (msl >> 8) & 0xFF;
18332+ buf[3] = msl & 0xFF;
18333+
18334+ buf[4] = (value >> 24) & 0xFF;
18335+ buf[5] = (value >> 16) & 0xFF;
18336+ buf[6] = (value >> 8) & 0xFF;
18337+ buf[7] = value & 0xFF;
18338+}
18339+
18340+/* }}} */
18341+
18342+/* Base64 Conversion */
18343+
18344+/* {{{ */
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'
18351+};
18352+
18353+static const char libssh2_base64_pad = '=';
18354+
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
18372+};
18373+
18374+/* }}} */
18375+
18376+
18377+/* {{{ libssh2_base64_decode
18378+ * Decode a base64 chunk and store it into a newly alloc'd buffer
18379+ */
18380+LIBSSH2_API int
18381+libssh2_base64_decode(LIBSSH2_SESSION * session, char **data,
18382+ unsigned int *datalen, const char *src,
18383+ unsigned int src_len)
18384+{
18385+ unsigned char *s, *d;
18386+ short v;
18387+ int i = 0, len = 0;
18388+
18389+ *data = LIBSSH2_ALLOC(session, (3 * src_len / 4) + 1);
18390+ d = (unsigned char *) *data;
18391+ if (!d) {
18392+ return -1;
18393+ }
18394+
18395+ for(s = (unsigned char *) src; ((char *) s) < (src + src_len); s++) {
18396+ if ((v = libssh2_base64_reverse_table[*s]) < 0)
18397+ continue;
18398+ switch (i % 4) {
18399+ case 0:
18400+ d[len] = v << 2;
18401+ break;
18402+ case 1:
18403+ d[len++] |= v >> 4;
18404+ d[len] = v << 4;
18405+ break;
18406+ case 2:
18407+ d[len++] |= v >> 2;
18408+ d[len] = v << 6;
18409+ break;
18410+ case 3:
18411+ d[len++] |= v;
18412+ break;
18413+ }
18414+ i++;
18415+ }
18416+ if ((i % 4) == 1) {
18417+ /* Invalid -- We have a byte which belongs exclusively to a partial octet */
18418+ LIBSSH2_FREE(session, *data);
18419+ return -1;
18420+ }
18421+
18422+ *datalen = len;
18423+ return 0;
18424+}
18425+
18426+/* }}} */
18427+
18428+#ifdef LIBSSH2DEBUG
18429+LIBSSH2_API int
18430+libssh2_trace(LIBSSH2_SESSION * session, int bitmask)
18431+{
18432+ session->showmask = bitmask;
18433+ return 0;
18434+}
18435+
18436+void
18437+_libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, ...)
18438+{
18439+ char buffer[1536];
18440+ int len;
18441+ va_list vargs;
18442+ static const char *const contexts[9] = {
18443+ "Unknown",
18444+ "Transport",
18445+ "Key Exchange",
18446+ "Userauth",
18447+ "Connection",
18448+ "scp",
18449+ "SFTP Subsystem",
18450+ "Failure Event",
18451+ "Publickey Subsystem",
18452+ };
18453+
18454+ if (context < 1 || context > 8) {
18455+ context = 0;
18456+ }
18457+ if (!(session->showmask & (1 << context))) {
18458+ /* no such output asked for */
18459+ return;
18460+ }
18461+
18462+ len = snprintf(buffer, 1535, "[libssh2] %s: ", contexts[context]);
18463+
18464+ va_start(vargs, format);
18465+ len += vsnprintf(buffer + len, 1535 - len, format, vargs);
18466+ buffer[len] = '\n';
18467+ va_end(vargs);
18468+ write(2, buffer, len + 1);
18469+
18470+}
18471+
18472+#else
18473+LIBSSH2_API int
18474+libssh2_trace(LIBSSH2_SESSION * session, int bitmask)
18475+{
18476+ (void) session;
18477+ (void) bitmask;
18478+ return 0;
18479+}
18480+#endif
18481
18482Property changes on: libssh2/src/misc.c
18483___________________________________________________________________
18484Added: svn:mime-type
18485 + text/x-c
18486Added: svn:keywords
18487 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
18488Added: cvs2svn:cvs-rev
18489 + 1.3
18490Added: svn:eol-style
18491 + native
18492
18493Index: libssh2/src/transport.c
18494===================================================================
18495--- libssh2/src/transport.c (.../tags/RELEASE_0_11_0)
18496+++ libssh2/src/transport.c (.../trunk)
18497@@ -0,0 +1,815 @@
18498+/* Copyright (C) 2007 The Written Word, Inc. All rights reserved.
18499+ * Author: Daniel Stenberg <daniel@haxx.se>
18500+ *
18501+ * Redistribution and use in source and binary forms,
18502+ * with or without modification, are permitted provided
18503+ * that the following conditions are met:
18504+ *
18505+ * Redistributions of source code must retain the above
18506+ * copyright notice, this list of conditions and the
18507+ * following disclaimer.
18508+ *
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.
18513+ *
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.
18518+ *
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.
18533+ *
18534+ * This file handles reading and writing to the SECSH transport layer. RFC4253.
18535+ */
18536+
18537+#include "libssh2_priv.h"
18538+#include <errno.h>
18539+#include <fcntl.h>
18540+
18541+#include <assert.h>
18542+
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 */
18545+
18546+#ifdef LIBSSH2DEBUG
18547+#define UNPRINTABLE_CHAR '.'
18548+static void
18549+debugdump(LIBSSH2_SESSION * session,
18550+ const char *desc, unsigned char *ptr, unsigned long size)
18551+{
18552+ size_t i;
18553+ size_t c;
18554+ FILE *stream = stdout;
18555+ unsigned int width = 0x10;
18556+
18557+ if (!(session->showmask & (1 << LIBSSH2_DBG_TRANS))) {
18558+ /* not asked for, bail out */
18559+ return;
18560+ }
18561+
18562+ fprintf(stream, "=> %s (%d bytes)\n", desc, (int) size);
18563+
18564+ for(i = 0; i < size; i += width) {
18565+
18566+ fprintf(stream, "%04lx: ", (long)i);
18567+
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]);
18572+ else
18573+ fputs(" ", stream);
18574+ }
18575+
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);
18580+ }
18581+ fputc('\n', stream); /* newline */
18582+ }
18583+ fflush(stream);
18584+}
18585+#else
18586+#define debugdump(a,x,y,z)
18587+#endif
18588+
18589+
18590+/* decrypt() decrypts 'len' bytes from 'source' to 'dest'.
18591+ *
18592+ * returns PACKET_NONE on success and PACKET_FAIL on failure
18593+ */
18594+
18595+static libssh2pack_t
18596+decrypt(LIBSSH2_SESSION * session, unsigned char *source,
18597+ unsigned char *dest, int len)
18598+{
18599+ struct transportpacket *p = &session->packet;
18600+ int blocksize = session->remote.crypt->blocksize;
18601+
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);
18605+
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;
18613+ }
18614+
18615+ /* if the crypt() function would write to a given address it
18616+ wouldn't have to memcpy() and we could avoid this memcpy()
18617+ too */
18618+ memcpy(dest, source, blocksize);
18619+
18620+ len -= blocksize; /* less bytes left */
18621+ dest += blocksize; /* advance write pointer */
18622+ source += blocksize; /* advance read pointer */
18623+ }
18624+ return PACKET_NONE; /* all is fine */
18625+}
18626+
18627+/*
18628+ * fullpacket() gets called when a full packet has been received and properly
18629+ * collected.
18630+ */
18631+static libssh2pack_t
18632+fullpacket(LIBSSH2_SESSION * session, int encrypted /* 1 or 0 */ )
18633+{
18634+ unsigned char macbuf[MAX_MACSIZE];
18635+ struct transportpacket *p = &session->packet;
18636+ int rc;
18637+
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;
18641+
18642+ if (encrypted) {
18643+
18644+ /* Calculate MAC hash */
18645+ session->remote.mac->hash(session, macbuf, /* store hash here */
18646+ session->remote.seqno,
18647+ p->init, 5,
18648+ p->payload,
18649+ session->fullpacket_payload_len,
18650+ &session->remote.mac_abstract);
18651+
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.
18656+ */
18657+ if (memcmp(macbuf, p->payload + session->fullpacket_payload_len,
18658+ session->remote.mac->mac_len)) {
18659+ session->fullpacket_macstate = LIBSSH2_MAC_INVALID;
18660+ }
18661+ }
18662+
18663+ session->remote.seqno++;
18664+
18665+ /* ignore the padding */
18666+ session->fullpacket_payload_len -= p->padding_length;
18667+
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;
18673+
18674+ if (session->remote.comp->comp(session, 0,
18675+ &data, &data_len,
18676+ LIBSSH2_PACKET_MAXDECOMP,
18677+ &free_payload,
18678+ p->payload,
18679+ session->fullpacket_payload_len,
18680+ &session->remote.comp_abstract)) {
18681+ LIBSSH2_FREE(session, p->payload);
18682+ return PACKET_FAIL;
18683+ }
18684+
18685+ if (free_payload) {
18686+ LIBSSH2_FREE(session, p->payload);
18687+ p->payload = data;
18688+ session->fullpacket_payload_len = data_len;
18689+ } else {
18690+ if (data == p->payload) {
18691+ /* It's not to be freed, because the
18692+ * compression layer reused payload, So let's
18693+ * do the same!
18694+ */
18695+ session->fullpacket_payload_len = data_len;
18696+ } else {
18697+ /* No comp_method actually lets this happen,
18698+ * but let's prepare for the future */
18699+
18700+ LIBSSH2_FREE(session, p->payload);
18701+
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",
18708+ 0);
18709+ return PACKET_ENOMEM;
18710+ }
18711+ memcpy(p->payload, data, data_len);
18712+ session->fullpacket_payload_len = data_len;
18713+ }
18714+ }
18715+ }
18716+
18717+ session->fullpacket_packet_type = p->payload[0];
18718+
18719+ debugdump(session, "libssh2_packet_read() plain",
18720+ p->payload, session->fullpacket_payload_len);
18721+
18722+ session->fullpacket_state = libssh2_NB_state_created;
18723+ }
18724+
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;
18733+ }
18734+ }
18735+
18736+ session->fullpacket_state = libssh2_NB_state_idle;
18737+
18738+ return session->fullpacket_packet_type;
18739+}
18740+
18741+
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
18746+ *
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
18749+ * packet.
18750+ */
18751+
18752+/*
18753+ * This function reads the binary stream as specified in chapter 6 of RFC4253
18754+ * "The Secure Shell (SSH) Transport Layer Protocol"
18755+ */
18756+libssh2pack_t
18757+libssh2_packet_read(LIBSSH2_SESSION * session)
18758+{
18759+ libssh2pack_t rc;
18760+ struct transportpacket *p = &session->packet;
18761+ int remainbuf;
18762+ int remainpack;
18763+ int numbytes;
18764+ int numdecrypt;
18765+ unsigned char block[MAX_BLOCKSIZE];
18766+ int blocksize;
18767+ int encrypted = 1;
18768+
18769+ int status;
18770+
18771+ /*
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!
18781+ */
18782+
18783+ if (session->state & LIBSSH2_STATE_EXCHANGING_KEYS &&
18784+ !(session->state & LIBSSH2_STATE_KEX_ACTIVE)) {
18785+
18786+ /* Whoever wants a packet won't get anything until the key re-exchange
18787+ * is done!
18788+ */
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;
18800+ }
18801+ }
18802+
18803+ /*
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
18807+ */
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;
18812+ }
18813+
18814+ do {
18815+ if (session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) {
18816+ return PACKET_NONE;
18817+ }
18818+
18819+ if (session->state & LIBSSH2_STATE_NEWKEYS) {
18820+ blocksize = session->remote.crypt->blocksize;
18821+ } else {
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 */
18825+ }
18826+
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. */
18832+
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;
18836+
18837+ /* if remainbuf turns negative we have a bad internal error */
18838+ assert(remainbuf >= 0);
18839+
18840+ if (remainbuf < blocksize) {
18841+ /* If we have less than a blocksize left, it is too
18842+ little data to deal with, read more */
18843+ ssize_t nread;
18844+
18845+ /* move any remainder to the start of the buffer so
18846+ that we can do a full refill */
18847+ if (remainbuf) {
18848+ memmove(p->buf, &p->buf[p->readidx], remainbuf);
18849+ p->readidx = 0;
18850+ p->writeidx = remainbuf;
18851+ } else {
18852+ /* nothing to move, just zero the indexes */
18853+ p->readidx = p->writeidx = 0;
18854+ }
18855+
18856+ /* now read a big chunk from the network into the temp buffer */
18857+ nread =
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 */
18864+#ifdef WIN32
18865+ switch (WSAGetLastError()) {
18866+ case WSAEWOULDBLOCK:
18867+ errno = EAGAIN;
18868+ break;
18869+
18870+ case WSAENOTSOCK:
18871+ errno = EBADF;
18872+ break;
18873+
18874+ case WSAENOTCONN:
18875+ case WSAECONNABORTED:
18876+ errno = WSAENOTCONN;
18877+ break;
18878+
18879+ case WSAEINTR:
18880+ errno = EINTR;
18881+ break;
18882+ }
18883+#endif /* WIN32 */
18884+ if ((nread < 0) && (errno == EAGAIN)) {
18885+ session->socket_block_directions =
18886+ LIBSSH2_SESSION_BLOCK_INBOUND;
18887+ return PACKET_EAGAIN;
18888+ }
18889+ return PACKET_FAIL;
18890+ }
18891+ debugdump(session, "libssh2_packet_read() raw",
18892+ &p->buf[remainbuf], nread);
18893+ /* advance write pointer */
18894+ p->writeidx += nread;
18895+
18896+ /* update remainbuf counter */
18897+ remainbuf = p->writeidx - p->readidx;
18898+ }
18899+
18900+ /* how much data to deal with from the buffer */
18901+ numbytes = remainbuf;
18902+
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. */
18907+
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
18912+ */
18913+ return PACKET_EAGAIN;
18914+ }
18915+
18916+ if (encrypted) {
18917+ rc = decrypt(session, &p->buf[p->readidx], block, blocksize);
18918+ if (rc != PACKET_NONE) {
18919+ return rc;
18920+ }
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);
18924+ } else {
18925+ /* the data is plain, just copy it verbatim to
18926+ the working block buffer */
18927+ memcpy(block, &p->buf[p->readidx], blocksize);
18928+ }
18929+
18930+ /* advance the read pointer */
18931+ p->readidx += blocksize;
18932+
18933+ /* we now have the initial blocksize bytes decrypted,
18934+ * and we can extract packet and padding length from it
18935+ */
18936+ p->packet_length = libssh2_ntohu32(block);
18937+ p->padding_length = block[4];
18938+
18939+ /* total_num is the number of bytes following the initial
18940+ (5 bytes) packet length and padding length fields */
18941+ p->total_num =
18942+ p->packet_length - 1 +
18943+ (encrypted ? session->remote.mac->mac_len : 0);
18944+
18945+ /* RFC4253 section 6.1 Maximum Packet Length says:
18946+ *
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.)."
18952+ */
18953+ if (p->total_num > LIBSSH2_PACKET_MAXPAYLOAD) {
18954+ return PACKET_TOOBIG;
18955+ }
18956+
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;
18962+ }
18963+ /* init write pointer to start of payload buffer */
18964+ p->wptr = p->payload;
18965+
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 */
18972+ }
18973+
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;
18977+
18978+ /* we already dealt with a blocksize worth of data */
18979+ numbytes -= blocksize;
18980+ }
18981+
18982+ /* how much there is left to add to the current payload
18983+ package */
18984+ remainpack = p->total_num - p->data_num;
18985+
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;
18990+ }
18991+
18992+ if (encrypted) {
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;
18998+
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;
19004+ } else {
19005+ int frac;
19006+ numdecrypt = numbytes;
19007+ frac = numdecrypt % blocksize;
19008+ if (frac) {
19009+ /* not an aligned amount of blocks,
19010+ align it */
19011+ numdecrypt -= frac;
19012+ /* and make it no unencrypted data
19013+ after it */
19014+ numbytes = 0;
19015+ }
19016+ }
19017+ } else {
19018+ /* unencrypted data should not be decrypted at all */
19019+ numdecrypt = 0;
19020+ }
19021+
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) {
19027+ return rc;
19028+ }
19029+
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;
19036+
19037+ /* bytes left to take care of without decryption */
19038+ numbytes -= numdecrypt;
19039+ }
19040+
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);
19045+
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;
19052+ }
19053+
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;
19057+
19058+ if (!remainpack) {
19059+ /* we have a full packet */
19060+ libssh2_packet_read_point1:
19061+ rc = fullpacket(session, encrypted);
19062+ if (rc == PACKET_EAGAIN) {
19063+
19064+ if (session->packAdd_state != libssh2_NB_state_idle)
19065+ {
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.
19073+ */
19074+ session->readPack_encrypted = encrypted;
19075+ session->readPack_state = libssh2_NB_state_jump1;
19076+ }
19077+
19078+ return PACKET_EAGAIN;
19079+ }
19080+
19081+ p->total_num = 0; /* no packet buffer available */
19082+
19083+ return rc;
19084+ }
19085+ } while (1); /* loop */
19086+
19087+ return PACKET_FAIL; /* we never reach this point */
19088+}
19089+
19090+/* }}} */
19091+
19092+static libssh2pack_t
19093+send_existing(LIBSSH2_SESSION * session, unsigned char *data,
19094+ unsigned long data_len, ssize_t * ret)
19095+{
19096+ ssize_t rc;
19097+ ssize_t length;
19098+ struct transportpacket *p = &session->packet;
19099+
19100+ if (!p->outbuf) {
19101+ *ret = 0;
19102+ return PACKET_NONE;
19103+ }
19104+
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
19111+ this case */
19112+ return PACKET_BADUSE;
19113+ }
19114+
19115+ *ret = 1; /* set to make our parent return */
19116+
19117+ /* number of bytes left to send */
19118+ length = p->ototal_num - p->osent;
19119+
19120+ rc = send(session->socket_fd, &p->outbuf[p->osent], length,
19121+ LIBSSH2_SOCKET_SEND_FLAGS(session));
19122+
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;
19133+ }
19134+ session->socket_block_directions = LIBSSH2_SESSION_BLOCK_OUTBOUND;
19135+ return PACKET_EAGAIN;
19136+ }
19137+
19138+ debugdump(session, "libssh2_packet_write send()", &p->outbuf[p->osent],
19139+ length);
19140+ p->osent += length; /* we sent away this much data */
19141+
19142+ return PACKET_NONE;
19143+}
19144+
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.
19148+ *
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.
19153+ *
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)
19157+ */
19158+int
19159+libssh2_packet_write(LIBSSH2_SESSION * session, unsigned char *data,
19160+ unsigned long data_len)
19161+{
19162+ int blocksize =
19163+ (session->state & LIBSSH2_STATE_NEWKEYS) ? session->local.crypt->
19164+ blocksize : 8;
19165+ int padding_length;
19166+ int packet_length;
19167+ int total_length;
19168+ int free_data = 0;
19169+#ifdef RANDOM_PADDING
19170+ int rand_max;
19171+ int seed = data[0]; /* FIXME: make this random */
19172+#endif
19173+ struct transportpacket *p = &session->packet;
19174+ int encrypted;
19175+ int i;
19176+ ssize_t ret;
19177+ libssh2pack_t rc;
19178+ unsigned char *orgdata = data;
19179+ unsigned long orgdata_len = data_len;
19180+
19181+ debugdump(session, "libssh2_packet_write plain", data, data_len);
19182+
19183+ /* FIRST, check if we have a pending write to complete */
19184+ rc = send_existing(session, data, data_len, &ret);
19185+ if (rc || ret) {
19186+ return rc;
19187+ }
19188+
19189+ encrypted = (session->state & LIBSSH2_STATE_NEWKEYS) ? 1 : 0;
19190+
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 */
19198+ }
19199+ }
19200+
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
19204+ larger. */
19205+
19206+ /* Plain math: (4 + 1 + packet_length + padding_length) % blocksize == 0 */
19207+
19208+ packet_length = data_len + 1 + 4; /* 1 is for padding_length field
19209+ 4 for the packet_length field */
19210+
19211+ /* at this point we have it all except the padding */
19212+
19213+ /* first figure out our minimum padding amount to make it an even
19214+ block size */
19215+ padding_length = blocksize - (packet_length % blocksize);
19216+
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;
19222+ }
19223+#ifdef RANDOM_PADDING
19224+ /* FIXME: we can add padding here, but that also makes the packets
19225+ bigger etc */
19226+
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
19229+ total */
19230+ rand_max = (255 - padding_length) / blocksize + 1;
19231+ padding_length += blocksize * (seed % rand_max);
19232+#endif
19233+
19234+ packet_length += padding_length;
19235+
19236+ /* append the MAC length to the total_length size */
19237+ total_length =
19238+ packet_length + (encrypted ? session->local.mac->mac_len : 0);
19239+
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
19242+ returns. */
19243+ p->outbuf = LIBSSH2_ALLOC(session, total_length);
19244+ if (!p->outbuf) {
19245+ return PACKET_ENOMEM;
19246+ }
19247+
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);
19257+ if (free_data) {
19258+ LIBSSH2_FREE(session, data);
19259+ }
19260+
19261+ if (encrypted) {
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);
19270+
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 */
19278+ }
19279+ }
19280+
19281+ session->local.seqno++;
19282+
19283+ ret = send(session->socket_fd, p->outbuf, total_length,
19284+ LIBSSH2_SOCKET_SEND_FLAGS(session));
19285+
19286+ if (ret != -1) {
19287+ debugdump(session, "libssh2_packet_write send()", p->outbuf, ret);
19288+ }
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;
19298+ }
19299+ return PACKET_FAIL;
19300+ }
19301+
19302+ /* the whole thing got sent away */
19303+ p->odata = NULL;
19304+ p->olen = 0;
19305+ LIBSSH2_FREE(session, p->outbuf);
19306+ p->outbuf = NULL;
19307+
19308+ return PACKET_NONE; /* all is good */
19309+}
19310+
19311+/* }}} */
19312+
19313
19314Property changes on: libssh2/src/transport.c
19315___________________________________________________________________
19316Added: svn:mime-type
19317 + text/x-c
19318Added: svn:keywords
19319 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
19320Added: cvs2svn:cvs-rev
19321 + 1.1
19322Added: svn:eol-style
19323 + native
19324Added: svn:executable
19325 + *
19326
19327
19328Property changes on: libssh2/src
19329___________________________________________________________________
19330Added: svn:ignore
19331 + libssh2_config.h
19332
19333
19334Index: package.xml
19335===================================================================
19336Cannot display: file marked as a binary type.
19337svn:mime-type = application/xml
19338
19339Property changes on: package.xml
19340___________________________________________________________________
19341Deleted: svn:mime-type
19342 - application/xml
19343
19344Index: ssh2_fopen_wrappers.c
19345===================================================================
19346--- ssh2_fopen_wrappers.c (.../tags/RELEASE_0_11_0)
19347+++ ssh2_fopen_wrappers.c (.../trunk)
19348@@ -46,7 +46,7 @@
19349 libssh2_channel_set_blocking(abstract->channel, abstract->is_blocking);
19350
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);
19354 }
19355
19356 static int php_ssh2_channel_stream_close(php_stream *stream, int close_handle TSRMLS_DC)
19357
19358Property changes on: ssh2_fopen_wrappers.c
19359___________________________________________________________________
19360Modified: cvs2svn:cvs-rev
19361 - 1.15
19362 + 1.16
19363
19364Index: php_ssh2.h
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;
19370 #endif
19371
19372+#ifndef PHP_WIN32
19373+#define closesocket(s) close(s)
19374+#endif
19375+
19376 #ifdef ZTS
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)
19381 #endif
19382
19383+#if (PHP_MAJOR_VERSION == 5) && (PHP_MINOR_VERSION >= 3)
19384+#define ZEND_IS_CALLABLE_TSRMLS_CC TSRMLS_CC
19385+#else
19386+#define ZEND_IS_CALLABLE_TSRMLS_CC
19387+#endif
19388+
19389 /* < 5.3 compatibility */
19390 #ifndef Z_REFCOUNT_P
19391 #define Z_REFCOUNT_P(pz) (pz)->refcount
19392
19393Property changes on: php_ssh2.h
19394___________________________________________________________________
19395Modified: cvs2svn:cvs-rev
19396 - 1.12
19397 + 1.14
19398
19399Index: EXPERIMENTAL
19400===================================================================
19401
19402Property changes on: EXPERIMENTAL
19403___________________________________________________________________
19404Added: svn:eol-style
19405 + native
19406Added: svn:keywords
19407 + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
19408Added: cvs2svn:cvs-rev
19409 + 1.1
19410
19411
19412Property changes on: .
19413___________________________________________________________________
19414Added: svn:ignore
19415 + #*#
19416*.dsw
19417*.la
19418*.lo
19419*.ncb
19420*.opt
19421*.plg
19422*.tgz
19423*~
19424.#*
19425.deps
19426.libs
19427Debug
19428Debug_TS
19429Makefile
19430Makefile.fragments
19431Makefile.global
19432Makefile.objects
19433Release
19434Release_TS
19435Release_TSDbg
19436Release_TS_inline
19437Release_inline
19438acinclude.m4
19439aclocal.m4
19440autom4te.cache
19441build
19442config.cache
19443config.guess
19444config.h
19445config.h.in
19446config.log
19447config.nice
19448config.status
19449config.sub
19450configure
19451configure.in
19452conftest
19453conftest.c
19454include
19455install-sh
19456libs.mk
19457libtool
19458ltmain.sh
19459missing
19460mkinstalldirs
19461modules
19462scan_makefile_in.awk
19463*.gcda
19464*.gcno
19465run-tests.php
19466
19467
This page took 3.587423 seconds and 4 git commands to generate.