1 /* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
2  * Copyright (c) 2005,2006 Mikhail Gusarov
3  * Copyright (c) 2009-2014 by Daniel Stenberg
4  * Copyright (c) 2010 Simon Josefsson
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms,
8  * with or without modification, are permitted provided
9  * that the following conditions are met:
10  *
11  *   Redistributions of source code must retain the above
12  *   copyright notice, this list of conditions and the
13  *   following disclaimer.
14  *
15  *   Redistributions in binary form must reproduce the above
16  *   copyright notice, this list of conditions and the following
17  *   disclaimer in the documentation and/or other materials
18  *   provided with the distribution.
19  *
20  *   Neither the name of the copyright holder nor the names
21  *   of any other contributors may be used to endorse or
22  *   promote products derived from this software without
23  *   specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
26  * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
27  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
28  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
30  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
32  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
33  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
35  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
36  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
37  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
38  * OF SUCH DAMAGE.
39  */
40 
41 #include "libssh2_priv.h"
42 #include <errno.h>
43 #include <fcntl.h>
44 
45 #ifdef HAVE_UNISTD_H
46 #include <unistd.h>
47 #endif
48 
49 #ifdef HAVE_SYS_TIME_H
50 #include <sys/time.h>
51 #endif
52 
53 #ifdef HAVE_INTTYPES_H
54 #include <inttypes.h>
55 #endif
56 
57 /* Needed for struct iovec on some platforms */
58 #ifdef HAVE_SYS_UIO_H
59 #include <sys/uio.h>
60 #endif
61 
62 #include <sys/types.h>
63 
64 #include "transport.h"
65 #include "channel.h"
66 #include "packet.h"
67 
68 /*
69  * libssh2_packet_queue_listener
70  *
71  * Queue a connection request for a listener
72  */
73 static inline int
packet_queue_listener(LIBSSH2_SESSION * session,unsigned char * data,unsigned long datalen,packet_queue_listener_state_t * listen_state)74 packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data,
75                       unsigned long datalen,
76                       packet_queue_listener_state_t *listen_state)
77 {
78     /*
79      * Look for a matching listener
80      */
81     /* 17 = packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */
82     unsigned long packet_len = 17 + (sizeof(FwdNotReq) - 1);
83     unsigned char *p;
84     LIBSSH2_LISTENER *listn = _libssh2_list_first(&session->listeners);
85     char failure_code = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;
86     int rc;
87 
88     if(listen_state->state == libssh2_NB_state_idle) {
89         unsigned long offset = (sizeof("forwarded-tcpip") - 1) + 5;
90         size_t temp_len = 0;
91         struct string_buf buf;
92         buf.data = data;
93         buf.dataptr = buf.data;
94         buf.len = datalen;
95 
96         if(datalen < offset) {
97             return _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY,
98                                   "Unexpected packet size");
99         }
100 
101         buf.dataptr += offset;
102 
103         if(_libssh2_get_u32(&buf, &(listen_state->sender_channel))) {
104             return _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
105                                   "Data too short extracting channel");
106         }
107         if(_libssh2_get_u32(&buf, &(listen_state->initial_window_size))) {
108             return _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
109                                   "Data too short extracting window size");
110         }
111         if(_libssh2_get_u32(&buf, &(listen_state->packet_size))) {
112             return _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
113                                   "Data too short extracting packet");
114         }
115         if(_libssh2_get_string(&buf, &(listen_state->host), &temp_len)) {
116             return _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
117                                   "Data too short extracting host");
118         }
119         listen_state->host_len = (uint32_t)temp_len;
120 
121         if(_libssh2_get_u32(&buf, &(listen_state->port))) {
122             return _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
123                                   "Data too short extracting port");
124         }
125         if(_libssh2_get_string(&buf, &(listen_state->shost), &temp_len)) {
126             return _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
127                                   "Data too short extracting shost");
128         }
129         listen_state->shost_len = (uint32_t)temp_len;
130 
131         if(_libssh2_get_u32(&buf, &(listen_state->sport))) {
132             return _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
133                                   "Data too short extracting sport");
134         }
135 
136         _libssh2_debug(session, LIBSSH2_TRACE_CONN,
137                        "Remote received connection from %s:%ld to %s:%ld",
138                        listen_state->shost, listen_state->sport,
139                        listen_state->host, listen_state->port);
140 
141         listen_state->state = libssh2_NB_state_allocated;
142     }
143 
144     if(listen_state->state != libssh2_NB_state_sent) {
145         while(listn) {
146             if((listn->port == (int) listen_state->port) &&
147                 (strlen(listn->host) == listen_state->host_len) &&
148                 (memcmp (listn->host, listen_state->host,
149                          listen_state->host_len) == 0)) {
150                 /* This is our listener */
151                 LIBSSH2_CHANNEL *channel = NULL;
152                 listen_state->channel = NULL;
153 
154                 if(listen_state->state == libssh2_NB_state_allocated) {
155                     if(listn->queue_maxsize &&
156                         (listn->queue_maxsize <= listn->queue_size)) {
157                         /* Queue is full */
158                         failure_code = SSH_OPEN_RESOURCE_SHORTAGE;
159                         _libssh2_debug(session, LIBSSH2_TRACE_CONN,
160                                        "Listener queue full, ignoring");
161                         listen_state->state = libssh2_NB_state_sent;
162                         break;
163                     }
164 
165                     channel = LIBSSH2_CALLOC(session, sizeof(LIBSSH2_CHANNEL));
166                     if(!channel) {
167                         _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
168                                        "Unable to allocate a channel for "
169                                        "new connection");
170                         failure_code = SSH_OPEN_RESOURCE_SHORTAGE;
171                         listen_state->state = libssh2_NB_state_sent;
172                         break;
173                     }
174                     listen_state->channel = channel;
175 
176                     channel->session = session;
177                     channel->channel_type_len = sizeof("forwarded-tcpip") - 1;
178                     channel->channel_type = LIBSSH2_ALLOC(session,
179                                                           channel->
180                                                           channel_type_len +
181                                                           1);
182                     if(!channel->channel_type) {
183                         _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
184                                        "Unable to allocate a channel for new"
185                                        " connection");
186                         LIBSSH2_FREE(session, channel);
187                         failure_code = SSH_OPEN_RESOURCE_SHORTAGE;
188                         listen_state->state = libssh2_NB_state_sent;
189                         break;
190                     }
191                     memcpy(channel->channel_type, "forwarded-tcpip",
192                            channel->channel_type_len + 1);
193 
194                     channel->remote.id = listen_state->sender_channel;
195                     channel->remote.window_size_initial =
196                         LIBSSH2_CHANNEL_WINDOW_DEFAULT;
197                     channel->remote.window_size =
198                         LIBSSH2_CHANNEL_WINDOW_DEFAULT;
199                     channel->remote.packet_size =
200                         LIBSSH2_CHANNEL_PACKET_DEFAULT;
201 
202                     channel->local.id = _libssh2_channel_nextid(session);
203                     channel->local.window_size_initial =
204                         listen_state->initial_window_size;
205                     channel->local.window_size =
206                         listen_state->initial_window_size;
207                     channel->local.packet_size = listen_state->packet_size;
208 
209                     _libssh2_debug(session, LIBSSH2_TRACE_CONN,
210                                    "Connection queued: channel %lu/%lu "
211                                    "win %lu/%lu packet %lu/%lu",
212                                    channel->local.id, channel->remote.id,
213                                    channel->local.window_size,
214                                    channel->remote.window_size,
215                                    channel->local.packet_size,
216                                    channel->remote.packet_size);
217 
218                     p = listen_state->packet;
219                     *(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION;
220                     _libssh2_store_u32(&p, channel->remote.id);
221                     _libssh2_store_u32(&p, channel->local.id);
222                     _libssh2_store_u32(&p,
223                                        channel->remote.window_size_initial);
224                     _libssh2_store_u32(&p, channel->remote.packet_size);
225 
226                     listen_state->state = libssh2_NB_state_created;
227                 }
228 
229                 if(listen_state->state == libssh2_NB_state_created) {
230                     rc = _libssh2_transport_send(session, listen_state->packet,
231                                                  17, NULL, 0);
232                     if(rc == LIBSSH2_ERROR_EAGAIN)
233                         return rc;
234                     else if(rc) {
235                         listen_state->state = libssh2_NB_state_idle;
236                         return _libssh2_error(session, rc,
237                                               "Unable to send channel "
238                                               "open confirmation");
239                     }
240 
241                     /* Link the channel into the end of the queue list */
242                     if(listen_state->channel) {
243                         _libssh2_list_add(&listn->queue,
244                                           &listen_state->channel->node);
245                         listn->queue_size++;
246                     }
247 
248                     listen_state->state = libssh2_NB_state_idle;
249                     return 0;
250                 }
251             }
252 
253             listn = _libssh2_list_next(&listn->node);
254         }
255 
256         listen_state->state = libssh2_NB_state_sent;
257     }
258 
259     /* We're not listening to you */
260     p = listen_state->packet;
261     *(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE;
262     _libssh2_store_u32(&p, listen_state->sender_channel);
263     _libssh2_store_u32(&p, failure_code);
264     _libssh2_store_str(&p, FwdNotReq, sizeof(FwdNotReq) - 1);
265     _libssh2_htonu32(p, 0);
266 
267     rc = _libssh2_transport_send(session, listen_state->packet,
268                                  packet_len, NULL, 0);
269     if(rc == LIBSSH2_ERROR_EAGAIN) {
270         return rc;
271     }
272     else if(rc) {
273         listen_state->state = libssh2_NB_state_idle;
274         return _libssh2_error(session, rc, "Unable to send open failure");
275 
276     }
277     listen_state->state = libssh2_NB_state_idle;
278     return 0;
279 }
280 
281 /*
282  * packet_x11_open
283  *
284  * Accept a forwarded X11 connection
285  */
286 static inline int
packet_x11_open(LIBSSH2_SESSION * session,unsigned char * data,unsigned long datalen,packet_x11_open_state_t * x11open_state)287 packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data,
288                 unsigned long datalen,
289                 packet_x11_open_state_t *x11open_state)
290 {
291     int failure_code = SSH_OPEN_CONNECT_FAILED;
292     /* 17 = packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */
293     unsigned long packet_len = 17 + (sizeof(X11FwdUnAvil) - 1);
294     unsigned char *p;
295     LIBSSH2_CHANNEL *channel = x11open_state->channel;
296     int rc;
297 
298     if(x11open_state->state == libssh2_NB_state_idle) {
299 
300         unsigned long offset = (sizeof("x11") - 1) + 5;
301         size_t temp_len = 0;
302         struct string_buf buf;
303         buf.data = data;
304         buf.dataptr = buf.data;
305         buf.len = datalen;
306 
307         if(datalen < offset) {
308             _libssh2_error(session, LIBSSH2_ERROR_INVAL,
309                            "unexpected data length");
310             failure_code = SSH_OPEN_CONNECT_FAILED;
311             goto x11_exit;
312         }
313 
314         buf.dataptr += offset;
315 
316         if(_libssh2_get_u32(&buf, &(x11open_state->sender_channel))) {
317             _libssh2_error(session, LIBSSH2_ERROR_INVAL,
318                            "unexpected sender channel size");
319             failure_code = SSH_OPEN_CONNECT_FAILED;
320             goto x11_exit;
321         }
322         if(_libssh2_get_u32(&buf, &(x11open_state->initial_window_size))) {
323             _libssh2_error(session, LIBSSH2_ERROR_INVAL,
324                            "unexpected window size");
325             failure_code = SSH_OPEN_CONNECT_FAILED;
326             goto x11_exit;
327         }
328         if(_libssh2_get_u32(&buf, &(x11open_state->packet_size))) {
329             _libssh2_error(session, LIBSSH2_ERROR_INVAL,
330                            "unexpected window size");
331             failure_code = SSH_OPEN_CONNECT_FAILED;
332             goto x11_exit;
333         }
334         if(_libssh2_get_string(&buf, &(x11open_state->shost), &temp_len)) {
335             _libssh2_error(session, LIBSSH2_ERROR_INVAL,
336                            "unexpected host size");
337             failure_code = SSH_OPEN_CONNECT_FAILED;
338             goto x11_exit;
339         }
340         x11open_state->shost_len = (uint32_t)temp_len;
341 
342         if(_libssh2_get_u32(&buf, &(x11open_state->sport))) {
343             _libssh2_error(session, LIBSSH2_ERROR_INVAL,
344                            "unexpected port size");
345             failure_code = SSH_OPEN_CONNECT_FAILED;
346             goto x11_exit;
347         }
348 
349         _libssh2_debug(session, LIBSSH2_TRACE_CONN,
350                        "X11 Connection Received from %s:%ld on channel %lu",
351                        x11open_state->shost, x11open_state->sport,
352                        x11open_state->sender_channel);
353 
354         x11open_state->state = libssh2_NB_state_allocated;
355     }
356 
357     if(session->x11) {
358         if(x11open_state->state == libssh2_NB_state_allocated) {
359             channel = LIBSSH2_CALLOC(session, sizeof(LIBSSH2_CHANNEL));
360             if(!channel) {
361                 _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
362                                "allocate a channel for new connection");
363                 failure_code = SSH_OPEN_RESOURCE_SHORTAGE;
364                 goto x11_exit;
365             }
366 
367             channel->session = session;
368             channel->channel_type_len = sizeof("x11") - 1;
369             channel->channel_type = LIBSSH2_ALLOC(session,
370                                                   channel->channel_type_len +
371                                                   1);
372             if(!channel->channel_type) {
373                 _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
374                                "allocate a channel for new connection");
375                 LIBSSH2_FREE(session, channel);
376                 failure_code = SSH_OPEN_RESOURCE_SHORTAGE;
377                 goto x11_exit;
378             }
379             memcpy(channel->channel_type, "x11",
380                    channel->channel_type_len + 1);
381 
382             channel->remote.id = x11open_state->sender_channel;
383             channel->remote.window_size_initial =
384                 LIBSSH2_CHANNEL_WINDOW_DEFAULT;
385             channel->remote.window_size = LIBSSH2_CHANNEL_WINDOW_DEFAULT;
386             channel->remote.packet_size = LIBSSH2_CHANNEL_PACKET_DEFAULT;
387 
388             channel->local.id = _libssh2_channel_nextid(session);
389             channel->local.window_size_initial =
390                 x11open_state->initial_window_size;
391             channel->local.window_size = x11open_state->initial_window_size;
392             channel->local.packet_size = x11open_state->packet_size;
393 
394             _libssh2_debug(session, LIBSSH2_TRACE_CONN,
395                            "X11 Connection established: channel %lu/%lu "
396                            "win %lu/%lu packet %lu/%lu",
397                            channel->local.id, channel->remote.id,
398                            channel->local.window_size,
399                            channel->remote.window_size,
400                            channel->local.packet_size,
401                            channel->remote.packet_size);
402             p = x11open_state->packet;
403             *(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION;
404             _libssh2_store_u32(&p, channel->remote.id);
405             _libssh2_store_u32(&p, channel->local.id);
406             _libssh2_store_u32(&p, channel->remote.window_size_initial);
407             _libssh2_store_u32(&p, channel->remote.packet_size);
408 
409             x11open_state->state = libssh2_NB_state_created;
410         }
411 
412         if(x11open_state->state == libssh2_NB_state_created) {
413             rc = _libssh2_transport_send(session, x11open_state->packet, 17,
414                                          NULL, 0);
415             if(rc == LIBSSH2_ERROR_EAGAIN) {
416                 return rc;
417             }
418             else if(rc) {
419                 x11open_state->state = libssh2_NB_state_idle;
420                 return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
421                                       "Unable to send channel open "
422                                       "confirmation");
423             }
424 
425             /* Link the channel into the session */
426             _libssh2_list_add(&session->channels, &channel->node);
427 
428             /*
429              * Pass control to the callback, they may turn right around and
430              * free the channel, or actually use it
431              */
432             LIBSSH2_X11_OPEN(channel, (char *)x11open_state->shost,
433                              x11open_state->sport);
434 
435             x11open_state->state = libssh2_NB_state_idle;
436             return 0;
437         }
438     }
439     else
440         failure_code = SSH_OPEN_RESOURCE_SHORTAGE;
441     /* fall-trough */
442   x11_exit:
443     p = x11open_state->packet;
444     *(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE;
445     _libssh2_store_u32(&p, x11open_state->sender_channel);
446     _libssh2_store_u32(&p, failure_code);
447     _libssh2_store_str(&p, X11FwdUnAvil, sizeof(X11FwdUnAvil) - 1);
448     _libssh2_htonu32(p, 0);
449 
450     rc = _libssh2_transport_send(session, x11open_state->packet, packet_len,
451                                  NULL, 0);
452     if(rc == LIBSSH2_ERROR_EAGAIN) {
453         return rc;
454     }
455     else if(rc) {
456         x11open_state->state = libssh2_NB_state_idle;
457         return _libssh2_error(session, rc, "Unable to send open failure");
458     }
459     x11open_state->state = libssh2_NB_state_idle;
460     return 0;
461 }
462 
463 /*
464  * _libssh2_packet_add
465  *
466  * Create a new packet and attach it to the brigade. Called from the transport
467  * layer when it has received a packet.
468  *
469  * The input pointer 'data' is pointing to allocated data that this function
470  * is asked to deal with so on failure OR success, it must be freed fine.
471  * The only exception is when the return code is LIBSSH2_ERROR_EAGAIN.
472  *
473  * This function will always be called with 'datalen' greater than zero.
474  */
475 int
_libssh2_packet_add(LIBSSH2_SESSION * session,unsigned char * data,size_t datalen,int macstate)476 _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
477                     size_t datalen, int macstate)
478 {
479     int rc = 0;
480     unsigned char *message = NULL;
481     unsigned char *language = NULL;
482     size_t message_len = 0;
483     size_t language_len = 0;
484     LIBSSH2_CHANNEL *channelp = NULL;
485     size_t data_head = 0;
486     unsigned char msg = data[0];
487 
488     switch(session->packAdd_state) {
489     case libssh2_NB_state_idle:
490         _libssh2_debug(session, LIBSSH2_TRACE_TRANS,
491                        "Packet type %d received, length=%d",
492                        (int) msg, (int) datalen);
493 
494         if((macstate == LIBSSH2_MAC_INVALID) &&
495             (!session->macerror ||
496              LIBSSH2_MACERROR(session, (char *) data, datalen))) {
497             /* Bad MAC input, but no callback set or non-zero return from the
498                callback */
499 
500             LIBSSH2_FREE(session, data);
501             return _libssh2_error(session, LIBSSH2_ERROR_INVALID_MAC,
502                                   "Invalid MAC received");
503         }
504         session->packAdd_state = libssh2_NB_state_allocated;
505         break;
506     case libssh2_NB_state_jump1:
507         goto libssh2_packet_add_jump_point1;
508     case libssh2_NB_state_jump2:
509         goto libssh2_packet_add_jump_point2;
510     case libssh2_NB_state_jump3:
511         goto libssh2_packet_add_jump_point3;
512     case libssh2_NB_state_jump4:
513         goto libssh2_packet_add_jump_point4;
514     case libssh2_NB_state_jump5:
515         goto libssh2_packet_add_jump_point5;
516     default: /* nothing to do */
517         break;
518     }
519 
520     if(session->packAdd_state == libssh2_NB_state_allocated) {
521         /* A couple exceptions to the packet adding rule: */
522         switch(msg) {
523 
524             /*
525               byte      SSH_MSG_DISCONNECT
526               uint32    reason code
527               string    description in ISO-10646 UTF-8 encoding [RFC3629]
528               string    language tag [RFC3066]
529             */
530 
531         case SSH_MSG_DISCONNECT:
532             if(datalen >= 5) {
533                 uint32_t reason = 0;
534                 struct string_buf buf;
535                 buf.data = (unsigned char *)data;
536                 buf.dataptr = buf.data;
537                 buf.len = datalen;
538                 buf.dataptr++; /* advance past type */
539 
540                 _libssh2_get_u32(&buf, &reason);
541                 _libssh2_get_string(&buf, &message, &message_len);
542                 _libssh2_get_string(&buf, &language, &language_len);
543 
544                 if(session->ssh_msg_disconnect) {
545                     LIBSSH2_DISCONNECT(session, reason, (const char *)message,
546                                        message_len, (const char *)language,
547                                        language_len);
548                 }
549 
550                 _libssh2_debug(session, LIBSSH2_TRACE_TRANS,
551                                "Disconnect(%d): %s(%s)", reason,
552                                message, language);
553             }
554 
555             LIBSSH2_FREE(session, data);
556             session->socket_state = LIBSSH2_SOCKET_DISCONNECTED;
557             session->packAdd_state = libssh2_NB_state_idle;
558             return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_DISCONNECT,
559                                   "socket disconnect");
560             /*
561               byte      SSH_MSG_IGNORE
562               string    data
563             */
564 
565         case SSH_MSG_IGNORE:
566             if(datalen >= 2) {
567                 if(session->ssh_msg_ignore) {
568                     LIBSSH2_IGNORE(session, (char *) data + 1, datalen - 1);
569                 }
570             }
571             else if(session->ssh_msg_ignore) {
572                 LIBSSH2_IGNORE(session, "", 0);
573             }
574             LIBSSH2_FREE(session, data);
575             session->packAdd_state = libssh2_NB_state_idle;
576             return 0;
577 
578             /*
579               byte      SSH_MSG_DEBUG
580               boolean   always_display
581               string    message in ISO-10646 UTF-8 encoding [RFC3629]
582               string    language tag [RFC3066]
583             */
584 
585         case SSH_MSG_DEBUG:
586             if(datalen >= 2) {
587                 int always_display = data[1];
588 
589                 if(datalen >= 6) {
590                     struct string_buf buf;
591                     buf.data = (unsigned char *)data;
592                     buf.dataptr = buf.data;
593                     buf.len = datalen;
594                     buf.dataptr += 2; /* advance past type & always display */
595 
596                     _libssh2_get_string(&buf, &message, &message_len);
597                     _libssh2_get_string(&buf, &language, &language_len);
598                 }
599 
600                 if(session->ssh_msg_debug) {
601                     LIBSSH2_DEBUG(session, always_display,
602                                   (const char *)message,
603                                   message_len, (const char *)language,
604                                   language_len);
605                 }
606             }
607 
608             /*
609              * _libssh2_debug will actually truncate this for us so
610              * that it's not an inordinate about of data
611              */
612             _libssh2_debug(session, LIBSSH2_TRACE_TRANS,
613                            "Debug Packet: %s", message);
614             LIBSSH2_FREE(session, data);
615             session->packAdd_state = libssh2_NB_state_idle;
616             return 0;
617 
618             /*
619               byte      SSH_MSG_GLOBAL_REQUEST
620               string    request name in US-ASCII only
621               boolean   want reply
622               ....      request-specific data follows
623             */
624 
625         case SSH_MSG_GLOBAL_REQUEST:
626             if(datalen >= 5) {
627                 uint32_t len = 0;
628                 unsigned char want_reply = 0;
629                 len = _libssh2_ntohu32(data + 1);
630                 if((len <= (UINT_MAX - 6)) && (datalen >= (6 + len))) {
631                     want_reply = data[5 + len];
632                     _libssh2_debug(session,
633                                    LIBSSH2_TRACE_CONN,
634                                    "Received global request type %.*s (wr %X)",
635                                    len, data + 5, want_reply);
636                 }
637 
638 
639                 if(want_reply) {
640                     static const unsigned char packet =
641                         SSH_MSG_REQUEST_FAILURE;
642                   libssh2_packet_add_jump_point5:
643                     session->packAdd_state = libssh2_NB_state_jump5;
644                     rc = _libssh2_transport_send(session, &packet, 1, NULL, 0);
645                     if(rc == LIBSSH2_ERROR_EAGAIN)
646                         return rc;
647                 }
648             }
649             LIBSSH2_FREE(session, data);
650             session->packAdd_state = libssh2_NB_state_idle;
651             return 0;
652 
653             /*
654               byte      SSH_MSG_CHANNEL_EXTENDED_DATA
655               uint32    recipient channel
656               uint32    data_type_code
657               string    data
658             */
659 
660         case SSH_MSG_CHANNEL_EXTENDED_DATA:
661             /* streamid(4) */
662             data_head += 4;
663 
664             /* fall-through */
665 
666             /*
667               byte      SSH_MSG_CHANNEL_DATA
668               uint32    recipient channel
669               string    data
670             */
671 
672         case SSH_MSG_CHANNEL_DATA:
673             /* packet_type(1) + channelno(4) + datalen(4) */
674             data_head += 9;
675 
676             if(datalen >= data_head)
677                 channelp =
678                     _libssh2_channel_locate(session,
679                                             _libssh2_ntohu32(data + 1));
680 
681             if(!channelp) {
682                 _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_UNKNOWN,
683                                "Packet received for unknown channel");
684                 LIBSSH2_FREE(session, data);
685                 session->packAdd_state = libssh2_NB_state_idle;
686                 return 0;
687             }
688 #ifdef LIBSSH2DEBUG
689             {
690                 uint32_t stream_id = 0;
691                 if(msg == SSH_MSG_CHANNEL_EXTENDED_DATA)
692                     stream_id = _libssh2_ntohu32(data + 5);
693 
694                 _libssh2_debug(session, LIBSSH2_TRACE_CONN,
695                                "%d bytes packet_add() for %lu/%lu/%lu",
696                                (int) (datalen - data_head),
697                                channelp->local.id,
698                                channelp->remote.id,
699                                stream_id);
700             }
701 #endif
702             if((channelp->remote.extended_data_ignore_mode ==
703                  LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE) &&
704                 (msg == SSH_MSG_CHANNEL_EXTENDED_DATA)) {
705                 /* Pretend we didn't receive this */
706                 LIBSSH2_FREE(session, data);
707 
708                 _libssh2_debug(session, LIBSSH2_TRACE_CONN,
709                                "Ignoring extended data and refunding %d bytes",
710                                (int) (datalen - 13));
711                 if(channelp->read_avail + datalen - data_head >=
712                     channelp->remote.window_size)
713                     datalen = channelp->remote.window_size -
714                         channelp->read_avail + data_head;
715 
716                 channelp->remote.window_size -= datalen - data_head;
717                 _libssh2_debug(session, LIBSSH2_TRACE_CONN,
718                                "shrinking window size by %lu bytes to %lu, "
719                                "read_avail %lu",
720                                datalen - data_head,
721                                channelp->remote.window_size,
722                                channelp->read_avail);
723 
724                 session->packAdd_channelp = channelp;
725 
726                 /* Adjust the window based on the block we just freed */
727               libssh2_packet_add_jump_point1:
728                 session->packAdd_state = libssh2_NB_state_jump1;
729                 rc = _libssh2_channel_receive_window_adjust(session->
730                                                             packAdd_channelp,
731                                                             datalen - 13,
732                                                             1, NULL);
733                 if(rc == LIBSSH2_ERROR_EAGAIN)
734                     return rc;
735 
736                 session->packAdd_state = libssh2_NB_state_idle;
737                 return 0;
738             }
739 
740             /*
741              * REMEMBER! remote means remote as source of data,
742              * NOT remote window!
743              */
744             if(channelp->remote.packet_size < (datalen - data_head)) {
745                 /*
746                  * Spec says we MAY ignore bytes sent beyond
747                  * packet_size
748                  */
749                 _libssh2_error(session,
750                                LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED,
751                                "Packet contains more data than we offered"
752                                " to receive, truncating");
753                 datalen = channelp->remote.packet_size + data_head;
754             }
755             if(channelp->remote.window_size <= channelp->read_avail) {
756                 /*
757                  * Spec says we MAY ignore bytes sent beyond
758                  * window_size
759                  */
760                 _libssh2_error(session,
761                                LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED,
762                                "The current receive window is full,"
763                                " data ignored");
764                 LIBSSH2_FREE(session, data);
765                 session->packAdd_state = libssh2_NB_state_idle;
766                 return 0;
767             }
768             /* Reset EOF status */
769             channelp->remote.eof = 0;
770 
771             if(channelp->read_avail + datalen - data_head >
772                 channelp->remote.window_size) {
773                 _libssh2_error(session,
774                                LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED,
775                                "Remote sent more data than current "
776                                "window allows, truncating");
777                 datalen = channelp->remote.window_size -
778                     channelp->read_avail + data_head;
779             }
780 
781             /* Update the read_avail counter. The window size will be
782              * updated once the data is actually read from the queue
783              * from an upper layer */
784             channelp->read_avail += datalen - data_head;
785 
786             _libssh2_debug(session, LIBSSH2_TRACE_CONN,
787                            "increasing read_avail by %lu bytes to %lu/%lu",
788                            (long)(datalen - data_head),
789                            (long)channelp->read_avail,
790                            (long)channelp->remote.window_size);
791 
792             break;
793 
794             /*
795               byte      SSH_MSG_CHANNEL_EOF
796               uint32    recipient channel
797             */
798 
799         case SSH_MSG_CHANNEL_EOF:
800             if(datalen >= 5)
801                 channelp =
802                     _libssh2_channel_locate(session,
803                                             _libssh2_ntohu32(data + 1));
804             if(!channelp)
805                 /* We may have freed already, just quietly ignore this... */
806                 ;
807             else {
808                 _libssh2_debug(session,
809                                LIBSSH2_TRACE_CONN,
810                                "EOF received for channel %lu/%lu",
811                                channelp->local.id,
812                                channelp->remote.id);
813                 channelp->remote.eof = 1;
814             }
815             LIBSSH2_FREE(session, data);
816             session->packAdd_state = libssh2_NB_state_idle;
817             return 0;
818 
819             /*
820               byte      SSH_MSG_CHANNEL_REQUEST
821               uint32    recipient channel
822               string    request type in US-ASCII characters only
823               boolean   want reply
824               ....      type-specific data follows
825             */
826 
827         case SSH_MSG_CHANNEL_REQUEST:
828             if(datalen >= 9) {
829                 uint32_t channel = _libssh2_ntohu32(data + 1);
830                 uint32_t len = _libssh2_ntohu32(data + 5);
831                 unsigned char want_reply = 1;
832 
833                 if((len + 9) < datalen)
834                     want_reply = data[len + 9];
835 
836                 _libssh2_debug(session,
837                                LIBSSH2_TRACE_CONN,
838                                "Channel %d received request type %.*s (wr %X)",
839                                channel, len, data + 9, want_reply);
840 
841                 if(len == sizeof("exit-status") - 1
842                     && (sizeof("exit-status") - 1 + 9) <= datalen
843                     && !memcmp("exit-status", data + 9,
844                                sizeof("exit-status") - 1)) {
845 
846                     /* we've got "exit-status" packet. Set the session value */
847                     if(datalen >= 20)
848                         channelp =
849                             _libssh2_channel_locate(session, channel);
850 
851                     if(channelp && (sizeof("exit-status") + 13) <= datalen) {
852                         channelp->exit_status =
853                             _libssh2_ntohu32(data + 9 + sizeof("exit-status"));
854                         _libssh2_debug(session, LIBSSH2_TRACE_CONN,
855                                        "Exit status %lu received for "
856                                        "channel %lu/%lu",
857                                        channelp->exit_status,
858                                        channelp->local.id,
859                                        channelp->remote.id);
860                     }
861 
862                 }
863                 else if(len == sizeof("exit-signal") - 1
864                          && (sizeof("exit-signal") - 1 + 9) <= datalen
865                          && !memcmp("exit-signal", data + 9,
866                                     sizeof("exit-signal") - 1)) {
867                     /* command terminated due to signal */
868                     if(datalen >= 20)
869                         channelp = _libssh2_channel_locate(session, channel);
870 
871                     if(channelp && (sizeof("exit-signal") + 13) <= datalen) {
872                         /* set signal name (without SIG prefix) */
873                         uint32_t namelen =
874                             _libssh2_ntohu32(data + 9 + sizeof("exit-signal"));
875 
876                         if(namelen <= UINT_MAX - 1) {
877                             channelp->exit_signal =
878                                 LIBSSH2_ALLOC(session, namelen + 1);
879                         }
880                         else {
881                             channelp->exit_signal = NULL;
882                         }
883 
884                         if(!channelp->exit_signal)
885                             rc = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
886                                                 "memory for signal name");
887                         else if((sizeof("exit-signal") + 13 + namelen <=
888                                  datalen)) {
889                             memcpy(channelp->exit_signal,
890                                    data + 13 + sizeof("exit-signal"), namelen);
891                             channelp->exit_signal[namelen] = '\0';
892                             /* TODO: save error message and language tag */
893                             _libssh2_debug(session, LIBSSH2_TRACE_CONN,
894                                            "Exit signal %s received for "
895                                            "channel %lu/%lu",
896                                            channelp->exit_signal,
897                                            channelp->local.id,
898                                            channelp->remote.id);
899                         }
900                     }
901                 }
902 
903 
904                 if(want_reply) {
905                     unsigned char packet[5];
906                   libssh2_packet_add_jump_point4:
907                     session->packAdd_state = libssh2_NB_state_jump4;
908                     packet[0] = SSH_MSG_CHANNEL_FAILURE;
909                     memcpy(&packet[1], data + 1, 4);
910                     rc = _libssh2_transport_send(session, packet, 5, NULL, 0);
911                     if(rc == LIBSSH2_ERROR_EAGAIN)
912                         return rc;
913                 }
914             }
915             LIBSSH2_FREE(session, data);
916             session->packAdd_state = libssh2_NB_state_idle;
917             return rc;
918 
919             /*
920               byte      SSH_MSG_CHANNEL_CLOSE
921               uint32    recipient channel
922             */
923 
924         case SSH_MSG_CHANNEL_CLOSE:
925             if(datalen >= 5)
926                 channelp =
927                     _libssh2_channel_locate(session,
928                                             _libssh2_ntohu32(data + 1));
929             if(!channelp) {
930                 /* We may have freed already, just quietly ignore this... */
931                 LIBSSH2_FREE(session, data);
932                 session->packAdd_state = libssh2_NB_state_idle;
933                 return 0;
934             }
935             _libssh2_debug(session, LIBSSH2_TRACE_CONN,
936                            "Close received for channel %lu/%lu",
937                            channelp->local.id,
938                            channelp->remote.id);
939 
940             channelp->remote.close = 1;
941             channelp->remote.eof = 1;
942 
943             LIBSSH2_FREE(session, data);
944             session->packAdd_state = libssh2_NB_state_idle;
945             return 0;
946 
947             /*
948               byte      SSH_MSG_CHANNEL_OPEN
949               string    "session"
950               uint32    sender channel
951               uint32    initial window size
952               uint32    maximum packet size
953             */
954 
955         case SSH_MSG_CHANNEL_OPEN:
956             if(datalen < 17)
957                 ;
958             else if((datalen >= (sizeof("forwarded-tcpip") + 4)) &&
959                      ((sizeof("forwarded-tcpip") - 1) ==
960                       _libssh2_ntohu32(data + 1))
961                      &&
962                      (memcmp(data + 5, "forwarded-tcpip",
963                              sizeof("forwarded-tcpip") - 1) == 0)) {
964 
965                 /* init the state struct */
966                 memset(&session->packAdd_Qlstn_state, 0,
967                        sizeof(session->packAdd_Qlstn_state));
968 
969               libssh2_packet_add_jump_point2:
970                 session->packAdd_state = libssh2_NB_state_jump2;
971                 rc = packet_queue_listener(session, data, datalen,
972                                            &session->packAdd_Qlstn_state);
973             }
974             else if((datalen >= (sizeof("x11") + 4)) &&
975                      ((sizeof("x11") - 1) == _libssh2_ntohu32(data + 1)) &&
976                      (memcmp(data + 5, "x11", sizeof("x11") - 1) == 0)) {
977 
978                 /* init the state struct */
979                 memset(&session->packAdd_x11open_state, 0,
980                        sizeof(session->packAdd_x11open_state));
981 
982               libssh2_packet_add_jump_point3:
983                 session->packAdd_state = libssh2_NB_state_jump3;
984                 rc = packet_x11_open(session, data, datalen,
985                                      &session->packAdd_x11open_state);
986             }
987             if(rc == LIBSSH2_ERROR_EAGAIN)
988                 return rc;
989 
990             LIBSSH2_FREE(session, data);
991             session->packAdd_state = libssh2_NB_state_idle;
992             return rc;
993 
994             /*
995               byte      SSH_MSG_CHANNEL_WINDOW_ADJUST
996               uint32    recipient channel
997               uint32    bytes to add
998             */
999         case SSH_MSG_CHANNEL_WINDOW_ADJUST:
1000             if(datalen < 9)
1001                 ;
1002             else {
1003                 uint32_t bytestoadd = _libssh2_ntohu32(data + 5);
1004                 channelp =
1005                     _libssh2_channel_locate(session,
1006                                             _libssh2_ntohu32(data + 1));
1007                 if(channelp) {
1008                     channelp->local.window_size += bytestoadd;
1009 
1010                     _libssh2_debug(session, LIBSSH2_TRACE_CONN,
1011                                    "Window adjust for channel %lu/%lu, "
1012                                    "adding %lu bytes, new window_size=%lu",
1013                                    channelp->local.id,
1014                                    channelp->remote.id,
1015                                    bytestoadd,
1016                                    channelp->local.window_size);
1017                 }
1018             }
1019             LIBSSH2_FREE(session, data);
1020             session->packAdd_state = libssh2_NB_state_idle;
1021             return 0;
1022         default:
1023             break;
1024         }
1025 
1026         session->packAdd_state = libssh2_NB_state_sent;
1027     }
1028 
1029     if(session->packAdd_state == libssh2_NB_state_sent) {
1030         LIBSSH2_PACKET *packetp =
1031             LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PACKET));
1032         if(!packetp) {
1033             _libssh2_debug(session, LIBSSH2_ERROR_ALLOC,
1034                            "memory for packet");
1035             LIBSSH2_FREE(session, data);
1036             session->packAdd_state = libssh2_NB_state_idle;
1037             return LIBSSH2_ERROR_ALLOC;
1038         }
1039         packetp->data = data;
1040         packetp->data_len = datalen;
1041         packetp->data_head = data_head;
1042 
1043         _libssh2_list_add(&session->packets, &packetp->node);
1044 
1045         session->packAdd_state = libssh2_NB_state_sent1;
1046     }
1047 
1048     if((msg == SSH_MSG_KEXINIT &&
1049          !(session->state & LIBSSH2_STATE_EXCHANGING_KEYS)) ||
1050         (session->packAdd_state == libssh2_NB_state_sent2)) {
1051         if(session->packAdd_state == libssh2_NB_state_sent1) {
1052             /*
1053              * Remote wants new keys
1054              * Well, it's already in the brigade,
1055              * let's just call back into ourselves
1056              */
1057             _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Renegotiating Keys");
1058 
1059             session->packAdd_state = libssh2_NB_state_sent2;
1060         }
1061 
1062         /*
1063          * The KEXINIT message has been added to the queue.  The packAdd and
1064          * readPack states need to be reset because _libssh2_kex_exchange
1065          * (eventually) calls upon _libssh2_transport_read to read the rest of
1066          * the key exchange conversation.
1067          */
1068         session->readPack_state = libssh2_NB_state_idle;
1069         session->packet.total_num = 0;
1070         session->packAdd_state = libssh2_NB_state_idle;
1071         session->fullpacket_state = libssh2_NB_state_idle;
1072 
1073         memset(&session->startup_key_state, 0, sizeof(key_exchange_state_t));
1074 
1075         /*
1076          * If there was a key reexchange failure, let's just hope we didn't
1077          * send NEWKEYS yet, otherwise remote will drop us like a rock
1078          */
1079         rc = _libssh2_kex_exchange(session, 1, &session->startup_key_state);
1080         if(rc == LIBSSH2_ERROR_EAGAIN)
1081             return rc;
1082     }
1083 
1084     session->packAdd_state = libssh2_NB_state_idle;
1085     return 0;
1086 }
1087 
1088 /*
1089  * _libssh2_packet_ask
1090  *
1091  * Scan the brigade for a matching packet type, optionally poll the socket for
1092  * a packet first
1093  */
1094 int
_libssh2_packet_ask(LIBSSH2_SESSION * session,unsigned char packet_type,unsigned char ** data,size_t * data_len,int match_ofs,const unsigned char * match_buf,size_t match_len)1095 _libssh2_packet_ask(LIBSSH2_SESSION * session, unsigned char packet_type,
1096                     unsigned char **data, size_t *data_len,
1097                     int match_ofs, const unsigned char *match_buf,
1098                     size_t match_len)
1099 {
1100     LIBSSH2_PACKET *packet = _libssh2_list_first(&session->packets);
1101 
1102     _libssh2_debug(session, LIBSSH2_TRACE_TRANS,
1103                    "Looking for packet of type: %d", (int) packet_type);
1104 
1105     while(packet) {
1106         if(packet->data[0] == packet_type
1107             && (packet->data_len >= (match_ofs + match_len))
1108             && (!match_buf ||
1109                 (memcmp(packet->data + match_ofs, match_buf,
1110                         match_len) == 0))) {
1111             *data = packet->data;
1112             *data_len = packet->data_len;
1113 
1114             /* unlink struct from session->packets */
1115             _libssh2_list_remove(&packet->node);
1116 
1117             LIBSSH2_FREE(session, packet);
1118 
1119             return 0;
1120         }
1121         packet = _libssh2_list_next(&packet->node);
1122     }
1123     return -1;
1124 }
1125 
1126 /*
1127  * libssh2_packet_askv
1128  *
1129  * Scan for any of a list of packet types in the brigade, optionally poll the
1130  * socket for a packet first
1131  */
1132 int
_libssh2_packet_askv(LIBSSH2_SESSION * session,const unsigned char * packet_types,unsigned char ** data,size_t * data_len,int match_ofs,const unsigned char * match_buf,size_t match_len)1133 _libssh2_packet_askv(LIBSSH2_SESSION * session,
1134                      const unsigned char *packet_types,
1135                      unsigned char **data, size_t *data_len,
1136                      int match_ofs,
1137                      const unsigned char *match_buf,
1138                      size_t match_len)
1139 {
1140     int i, packet_types_len = strlen((char *) packet_types);
1141 
1142     for(i = 0; i < packet_types_len; i++) {
1143         if(0 == _libssh2_packet_ask(session, packet_types[i], data,
1144                                      data_len, match_ofs,
1145                                      match_buf, match_len)) {
1146             return 0;
1147         }
1148     }
1149 
1150     return -1;
1151 }
1152 
1153 /*
1154  * _libssh2_packet_require
1155  *
1156  * Loops _libssh2_transport_read() until the packet requested is available
1157  * SSH_DISCONNECT or a SOCKET_DISCONNECTED will cause a bailout
1158  *
1159  * Returns negative on error
1160  * Returns 0 when it has taken care of the requested packet.
1161  */
1162 int
_libssh2_packet_require(LIBSSH2_SESSION * session,unsigned char packet_type,unsigned char ** data,size_t * data_len,int match_ofs,const unsigned char * match_buf,size_t match_len,packet_require_state_t * state)1163 _libssh2_packet_require(LIBSSH2_SESSION * session, unsigned char packet_type,
1164                         unsigned char **data, size_t *data_len,
1165                         int match_ofs,
1166                         const unsigned char *match_buf,
1167                         size_t match_len,
1168                         packet_require_state_t *state)
1169 {
1170     if(state->start == 0) {
1171         if(_libssh2_packet_ask(session, packet_type, data, data_len,
1172                                 match_ofs, match_buf,
1173                                 match_len) == 0) {
1174             /* A packet was available in the packet brigade */
1175             return 0;
1176         }
1177 
1178         state->start = time(NULL);
1179     }
1180 
1181     while(session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
1182         int ret = _libssh2_transport_read(session);
1183         if(ret == LIBSSH2_ERROR_EAGAIN)
1184             return ret;
1185         else if(ret < 0) {
1186             state->start = 0;
1187             /* an error which is not just because of blocking */
1188             return ret;
1189         }
1190         else if(ret == packet_type) {
1191             /* Be lazy, let packet_ask pull it out of the brigade */
1192             ret = _libssh2_packet_ask(session, packet_type, data, data_len,
1193                                       match_ofs, match_buf, match_len);
1194             state->start = 0;
1195             return ret;
1196         }
1197         else if(ret == 0) {
1198             /* nothing available, wait until data arrives or we time out */
1199             long left = LIBSSH2_READ_TIMEOUT - (long)(time(NULL) -
1200                                                       state->start);
1201 
1202             if(left <= 0) {
1203                 state->start = 0;
1204                 return LIBSSH2_ERROR_TIMEOUT;
1205             }
1206             return -1; /* no packet available yet */
1207         }
1208     }
1209 
1210     /* Only reached if the socket died */
1211     return LIBSSH2_ERROR_SOCKET_DISCONNECT;
1212 }
1213 
1214 /*
1215  * _libssh2_packet_burn
1216  *
1217  * Loops _libssh2_transport_read() until any packet is available and promptly
1218  * discards it.
1219  * Used during KEX exchange to discard badly guessed KEX_INIT packets
1220  */
1221 int
_libssh2_packet_burn(LIBSSH2_SESSION * session,libssh2_nonblocking_states * state)1222 _libssh2_packet_burn(LIBSSH2_SESSION * session,
1223                      libssh2_nonblocking_states * state)
1224 {
1225     unsigned char *data;
1226     size_t data_len;
1227     unsigned char i, all_packets[255];
1228     int ret;
1229 
1230     if(*state == libssh2_NB_state_idle) {
1231         for(i = 1; i < 255; i++) {
1232             all_packets[i - 1] = i;
1233         }
1234         all_packets[254] = 0;
1235 
1236         if(_libssh2_packet_askv(session, all_packets, &data, &data_len, 0,
1237                                  NULL, 0) == 0) {
1238             i = data[0];
1239             /* A packet was available in the packet brigade, burn it */
1240             LIBSSH2_FREE(session, data);
1241             return i;
1242         }
1243 
1244         _libssh2_debug(session, LIBSSH2_TRACE_TRANS,
1245                        "Blocking until packet becomes available to burn");
1246         *state = libssh2_NB_state_created;
1247     }
1248 
1249     while(session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
1250         ret = _libssh2_transport_read(session);
1251         if(ret == LIBSSH2_ERROR_EAGAIN) {
1252             return ret;
1253         }
1254         else if(ret < 0) {
1255             *state = libssh2_NB_state_idle;
1256             return ret;
1257         }
1258         else if(ret == 0) {
1259             /* FIXME: this might busyloop */
1260             continue;
1261         }
1262 
1263         /* Be lazy, let packet_ask pull it out of the brigade */
1264         if(0 ==
1265             _libssh2_packet_ask(session, (unsigned char)ret,
1266                                          &data, &data_len, 0, NULL, 0)) {
1267             /* Smoke 'em if you got 'em */
1268             LIBSSH2_FREE(session, data);
1269             *state = libssh2_NB_state_idle;
1270             return ret;
1271         }
1272     }
1273 
1274     /* Only reached if the socket died */
1275     return LIBSSH2_ERROR_SOCKET_DISCONNECT;
1276 }
1277 
1278 /*
1279  * _libssh2_packet_requirev
1280  *
1281  * Loops _libssh2_transport_read() until one of a list of packet types
1282  * requested is available. SSH_DISCONNECT or a SOCKET_DISCONNECTED will cause
1283  * a bailout. packet_types is a null terminated list of packet_type numbers
1284  */
1285 
1286 int
_libssh2_packet_requirev(LIBSSH2_SESSION * session,const unsigned char * packet_types,unsigned char ** data,size_t * data_len,int match_ofs,const unsigned char * match_buf,size_t match_len,packet_requirev_state_t * state)1287 _libssh2_packet_requirev(LIBSSH2_SESSION *session,
1288                          const unsigned char *packet_types,
1289                          unsigned char **data, size_t *data_len,
1290                          int match_ofs,
1291                          const unsigned char *match_buf, size_t match_len,
1292                          packet_requirev_state_t * state)
1293 {
1294     if(_libssh2_packet_askv(session, packet_types, data, data_len, match_ofs,
1295                              match_buf, match_len) == 0) {
1296         /* One of the packets listed was available in the packet brigade */
1297         state->start = 0;
1298         return 0;
1299     }
1300 
1301     if(state->start == 0) {
1302         state->start = time(NULL);
1303     }
1304 
1305     while(session->socket_state != LIBSSH2_SOCKET_DISCONNECTED) {
1306         int ret = _libssh2_transport_read(session);
1307         if((ret < 0) && (ret != LIBSSH2_ERROR_EAGAIN)) {
1308             state->start = 0;
1309             return ret;
1310         }
1311         if(ret <= 0) {
1312             long left = LIBSSH2_READ_TIMEOUT -
1313                 (long)(time(NULL) - state->start);
1314 
1315             if(left <= 0) {
1316                 state->start = 0;
1317                 return LIBSSH2_ERROR_TIMEOUT;
1318             }
1319             else if(ret == LIBSSH2_ERROR_EAGAIN) {
1320                 return ret;
1321             }
1322         }
1323 
1324         if(strchr((char *) packet_types, ret)) {
1325             /* Be lazy, let packet_ask pull it out of the brigade */
1326             return _libssh2_packet_askv(session, packet_types, data,
1327                                         data_len, match_ofs, match_buf,
1328                                         match_len);
1329         }
1330     }
1331 
1332     /* Only reached if the socket died */
1333     state->start = 0;
1334     return LIBSSH2_ERROR_SOCKET_DISCONNECT;
1335 }
1336 
1337