]> git.pld-linux.org Git - packages/php-pecl-ssh2.git/blob - branch.diff
- php 5.5 rebuild
[packages/php-pecl-ssh2.git] / branch.diff
1 Index: 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
44 Property changes on: config.w32
45 ___________________________________________________________________
46 Added: svn:eol-style
47    + native
48 Added: svn:keywords
49    + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
50 Added: cvs2svn:cvs-rev
51    + 1.11
52
53 Index: 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
154 Property changes on: ssh2.c
155 ___________________________________________________________________
156 Modified: cvs2svn:cvs-rev
157    - 1.22
158    + 1.25
159
160 Index: libssh2/include/libssh2_publickey.h
161 ===================================================================
162 --- libssh2/include/libssh2_publickey.h (.../tags/RELEASE_0_11_0)
163 +++ libssh2/include/libssh2_publickey.h (.../trunk)
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
267 Property changes on: libssh2/include/libssh2_publickey.h
268 ___________________________________________________________________
269 Added: svn:mime-type
270    + text/x-c
271 Added: svn:keywords
272    + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
273 Added: cvs2svn:cvs-rev
274    + 1.2
275 Added: svn:eol-style
276    + native
277
278 Index: libssh2/include/libssh2_sftp.h
279 ===================================================================
280 --- libssh2/include/libssh2_sftp.h      (.../tags/RELEASE_0_11_0)
281 +++ libssh2/include/libssh2_sftp.h      (.../trunk)
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
535 Property changes on: libssh2/include/libssh2_sftp.h
536 ___________________________________________________________________
537 Added: svn:mime-type
538    + text/x-c
539 Added: svn:keywords
540    + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
541 Added: cvs2svn:cvs-rev
542    + 1.2
543 Added: svn:eol-style
544    + native
545
546 Index: 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
1041 Property changes on: libssh2/include/libssh2.h
1042 ___________________________________________________________________
1043 Added: svn:mime-type
1044    + text/x-c
1045 Added: svn:keywords
1046    + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
1047 Added: cvs2svn:cvs-rev
1048    + 1.3
1049 Added: svn:eol-style
1050    + native
1051
1052 Index: 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
1398 Property changes on: libssh2/src/comp.c
1399 ___________________________________________________________________
1400 Added: svn:mime-type
1401    + text/x-c
1402 Added: svn:keywords
1403    + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
1404 Added: cvs2svn:cvs-rev
1405    + 1.2
1406 Added: svn:eol-style
1407    + native
1408
1409 Index: 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
1975 Property changes on: libssh2/src/libgcrypt.c
1976 ___________________________________________________________________
1977 Added: svn:mime-type
1978    + text/x-c
1979 Added: svn:keywords
1980    + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
1981 Added: cvs2svn:cvs-rev
1982    + 1.1
1983 Added: svn:eol-style
1984    + native
1985 Added: svn:executable
1986    + *
1987
1988 Index: 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
3467 Property changes on: libssh2/src/userauth.c
3468 ___________________________________________________________________
3469 Added: svn:mime-type
3470    + text/x-c
3471 Added: svn:keywords
3472    + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
3473 Added: cvs2svn:cvs-rev
3474    + 1.2
3475 Added: svn:eol-style
3476    + native
3477
3478 Index: 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
3795 Property changes on: libssh2/src/mac.c
3796 ___________________________________________________________________
3797 Added: svn:mime-type
3798    + text/x-c
3799 Added: svn:keywords
3800    + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
3801 Added: cvs2svn:cvs-rev
3802    + 1.2
3803 Added: svn:eol-style
3804    + native
3805
3806 Index: 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
4068 Property changes on: libssh2/src/crypt.c
4069 ___________________________________________________________________
4070 Added: svn:mime-type
4071    + text/x-c
4072 Added: svn:keywords
4073    + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
4074 Added: cvs2svn:cvs-rev
4075    + 1.2
4076 Added: svn:eol-style
4077    + native
4078
4079 Index: 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
4272 Property changes on: libssh2/src/libgcrypt.h
4273 ___________________________________________________________________
4274 Added: svn:mime-type
4275    + text/x-c
4276 Added: svn:keywords
4277    + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
4278 Added: cvs2svn:cvs-rev
4279    + 1.1
4280 Added: svn:eol-style
4281    + native
4282 Added: svn:executable
4283    + *
4284
4285 Index: 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
5561 Property changes on: libssh2/src/packet.c
5562 ___________________________________________________________________
5563 Added: svn:mime-type
5564    + text/x-c
5565 Added: svn:keywords
5566    + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
5567 Added: cvs2svn:cvs-rev
5568    + 1.2
5569 Added: svn:eol-style
5570    + native
5571
5572 Index: 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
7838 Property changes on: libssh2/src/channel.c
7839 ___________________________________________________________________
7840 Added: svn:mime-type
7841    + text/x-c
7842 Added: svn:keywords
7843    + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
7844 Added: cvs2svn:cvs-rev
7845    + 1.2
7846 Added: svn:eol-style
7847    + native
7848
7849 Index: libssh2/src/libssh2_priv.h
7850 ===================================================================
7851 --- libssh2/src/libssh2_priv.h  (.../tags/RELEASE_0_11_0)
7852 +++ libssh2/src/libssh2_priv.h  (.../trunk)
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
9066 Property changes on: libssh2/src/libssh2_priv.h
9067 ___________________________________________________________________
9068 Added: svn:mime-type
9069    + text/x-c
9070 Added: svn:keywords
9071    + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
9072 Added: cvs2svn:cvs-rev
9073    + 1.1
9074 Added: svn:eol-style
9075    + native
9076 Added: svn:executable
9077    + *
9078
9079 Index: 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
11443 Property changes on: libssh2/src/sftp.c
11444 ___________________________________________________________________
11445 Added: svn:mime-type
11446    + text/x-c
11447 Added: svn:keywords
11448    + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
11449 Added: cvs2svn:cvs-rev
11450    + 1.2
11451 Added: svn:eol-style
11452    + native
11453
11454 Index: libssh2/src/libssh2_config.h.in.w32
11455 ===================================================================
11456 --- libssh2/src/libssh2_config.h.in.w32 (.../tags/RELEASE_0_11_0)
11457 +++ libssh2/src/libssh2_config.h.in.w32 (.../trunk)
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
11504 Property changes on: libssh2/src/libssh2_config.h.in.w32
11505 ___________________________________________________________________
11506 Added: svn:keywords
11507    + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
11508 Added: cvs2svn:cvs-rev
11509    + 1.1
11510 Added: svn:eol-style
11511    + native
11512 Added: svn:executable
11513    + *
11514
11515 Index: 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
11730 Property changes on: libssh2/src/pem.c
11731 ___________________________________________________________________
11732 Added: svn:mime-type
11733    + text/x-c
11734 Added: svn:keywords
11735    + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
11736 Added: cvs2svn:cvs-rev
11737    + 1.1
11738 Added: svn:eol-style
11739    + native
11740 Added: svn:executable
11741    + *
11742
11743 Index: 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
13303 Property changes on: libssh2/src/session.c
13304 ___________________________________________________________________
13305 Added: svn:mime-type
13306    + text/x-c
13307 Added: svn:keywords
13308    + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
13309 Added: cvs2svn:cvs-rev
13310    + 1.3
13311 Added: svn:eol-style
13312    + native
13313
13314 Index: 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
13636 Property changes on: libssh2/src/openssl.c
13637 ___________________________________________________________________
13638 Added: svn:mime-type
13639    + text/x-c
13640 Added: svn:keywords
13641    + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
13642 Added: cvs2svn:cvs-rev
13643    + 1.1
13644 Added: svn:eol-style
13645    + native
13646 Added: svn:executable
13647    + *
13648
13649 Index: 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
14466 Property changes on: libssh2/src/scp.c
14467 ___________________________________________________________________
14468 Added: svn:mime-type
14469    + text/x-c
14470 Added: svn:keywords
14471    + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
14472 Added: cvs2svn:cvs-rev
14473    + 1.2
14474 Added: svn:eol-style
14475    + native
14476
14477 Index: 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
14938 Property changes on: libssh2/src/hostkey.c
14939 ___________________________________________________________________
14940 Added: svn:mime-type
14941    + text/x-c
14942 Added: svn:keywords
14943    + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
14944 Added: cvs2svn:cvs-rev
14945    + 1.2
14946 Added: svn:eol-style
14947    + native
14948
14949 Index: 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
16049 Property changes on: libssh2/src/publickey.c
16050 ___________________________________________________________________
16051 Added: svn:mime-type
16052    + text/x-c
16053 Added: svn:keywords
16054    + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
16055 Added: cvs2svn:cvs-rev
16056    + 1.4
16057 Added: svn:eol-style
16058    + native
16059
16060 Index: 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
17982 Property changes on: libssh2/src/kex.c
17983 ___________________________________________________________________
17984 Added: svn:mime-type
17985    + text/x-c
17986 Added: svn:keywords
17987    + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
17988 Added: cvs2svn:cvs-rev
17989    + 1.3
17990 Added: svn:eol-style
17991    + native
17992
17993 Index: 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
18223 Property changes on: libssh2/src/openssl.h
18224 ___________________________________________________________________
18225 Added: svn:mime-type
18226    + text/x-c
18227 Added: svn:keywords
18228    + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
18229 Added: cvs2svn:cvs-rev
18230    + 1.1
18231 Added: svn:eol-style
18232    + native
18233 Added: svn:executable
18234    + *
18235
18236 Index: 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
18482 Property changes on: libssh2/src/misc.c
18483 ___________________________________________________________________
18484 Added: svn:mime-type
18485    + text/x-c
18486 Added: svn:keywords
18487    + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
18488 Added: cvs2svn:cvs-rev
18489    + 1.3
18490 Added: svn:eol-style
18491    + native
18492
18493 Index: 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
19314 Property changes on: libssh2/src/transport.c
19315 ___________________________________________________________________
19316 Added: svn:mime-type
19317    + text/x-c
19318 Added: svn:keywords
19319    + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
19320 Added: cvs2svn:cvs-rev
19321    + 1.1
19322 Added: svn:eol-style
19323    + native
19324 Added: svn:executable
19325    + *
19326
19327
19328 Property changes on: libssh2/src
19329 ___________________________________________________________________
19330 Added: svn:ignore
19331    + libssh2_config.h
19332
19333
19334 Index: package.xml
19335 ===================================================================
19336 Cannot display: file marked as a binary type.
19337 svn:mime-type = application/xml
19338
19339 Property changes on: package.xml
19340 ___________________________________________________________________
19341 Deleted: svn:mime-type
19342    - application/xml
19343
19344 Index: 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
19358 Property changes on: ssh2_fopen_wrappers.c
19359 ___________________________________________________________________
19360 Modified: cvs2svn:cvs-rev
19361    - 1.15
19362    + 1.16
19363
19364 Index: 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
19393 Property changes on: php_ssh2.h
19394 ___________________________________________________________________
19395 Modified: cvs2svn:cvs-rev
19396    - 1.12
19397    + 1.14
19398
19399 Index: EXPERIMENTAL
19400 ===================================================================
19401
19402 Property changes on: EXPERIMENTAL
19403 ___________________________________________________________________
19404 Added: svn:eol-style
19405    + native
19406 Added: svn:keywords
19407    + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
19408 Added: cvs2svn:cvs-rev
19409    + 1.1
19410
19411
19412 Property changes on: .
19413 ___________________________________________________________________
19414 Added: svn:ignore
19415    + #*#
19416 *.dsw
19417 *.la
19418 *.lo
19419 *.ncb
19420 *.opt
19421 *.plg
19422 *.tgz
19423 *~
19424 .#*
19425 .deps
19426 .libs
19427 Debug
19428 Debug_TS
19429 Makefile
19430 Makefile.fragments
19431 Makefile.global
19432 Makefile.objects
19433 Release
19434 Release_TS
19435 Release_TSDbg
19436 Release_TS_inline
19437 Release_inline
19438 acinclude.m4
19439 aclocal.m4
19440 autom4te.cache
19441 build
19442 config.cache
19443 config.guess
19444 config.h
19445 config.h.in
19446 config.log
19447 config.nice
19448 config.status
19449 config.sub
19450 configure
19451 configure.in
19452 conftest
19453 conftest.c
19454 include
19455 install-sh
19456 libs.mk
19457 libtool
19458 ltmain.sh
19459 missing
19460 mkinstalldirs
19461 modules
19462 scan_makefile_in.awk
19463 *.gcda
19464 *.gcno
19465 run-tests.php
19466
19467
This page took 2.286912 seconds and 3 git commands to generate.