cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
ssh2_chn.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib SSHv2 Channel Management *
4 * Copyright Peter Gutmann 1998-2008 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "crypt.h"
10  #include "misc_rw.h"
11  #include "session.h"
12  #include "ssh.h"
13 #else
14  #include "crypt.h"
15  #include "enc_dec/misc_rw.h"
16  #include "session/session.h"
17  #include "session/ssh.h"
18 #endif /* Compiler-specific includes */
19 
20 /* Channel flags */
21 
22 #define CHANNEL_FLAG_NONE 0x00 /* No channel flag */
23 #define CHANNEL_FLAG_ACTIVE 0x01 /* Channel is active */
24 #define CHANNEL_FLAG_WRITECLOSED 0x02 /* Write-side of ch.closed */
25 
26 /* Per-channel information. SSH channel IDs are 32-bit/4 byte data values
27  and can be reused during sessions so we provide our own guaranteed-unique
28  short int ID for users to identify a particular channel. Since each
29  channel can have its own distinct characteristics we have to record
30  information like the window size and count and packet size information on
31  a per-channel basis. In addition if the channel is tied to a forwarded
32  port we also record port-forwarding information in the generic channel-
33  type and channel-type-argument strings */
34 
35 typedef struct {
36  /* General channel information. The read and write channel numbers are
37  the same for everything but Cisco software */
38  int channelID; /* cryptlib-level channel ID */
39  long readChannelNo, writeChannelNo; /* SSH-level channel ID */
40  int flags; /* Channel flags */
41 
42  /* External interface information */
43  CRYPT_ATTRIBUTE_TYPE cursorPos; /* Virtual cursor position */
44 
45  /* Channel parameters */
46  int windowCount, windowSize; /* Current window usage and tot.size */
47  int maxPacketSize; /* Max allowed packet size */
48 
49  /* Channel naming information */
51  char type[ CRYPT_MAX_TEXTSIZE + 8 ];
53  char arg1[ CRYPT_MAX_TEXTSIZE + 8 ];
54  BUFFER( CRYPT_MAX_TEXTSIZE, arg2Len ) \
55  char arg2[ CRYPT_MAX_TEXTSIZE + 8 ];
56  int typeLen, arg1Len, arg2Len;
57 
58  /* Channel extra data. This contains encoded oddball protocol-specific
59  SSH packets to be sent or having been received */
62  ( UINT_SIZE * 4 ) + 8 ];
64 
65 /* Check whether a channel corresponds to a null channel (a placeholder used
66  when there's currently no channel active) and whether a channel is
67  currently active */
68 
69 #define isNullChannel( channelInfoPtr ) \
70  ( ( channelInfoPtr )->readChannelNo == UNUSED_CHANNEL_NO )
71 #define isActiveChannel( channelInfoPtr ) \
72  ( channelInfoPtr->flags & CHANNEL_FLAG_ACTIVE )
73 
74 /* The maximum allowed number of channels */
75 
76 #ifdef USE_SSH_EXTENDED
77  #define SSH_MAX_CHANNELS 4
78 #else
79  #define SSH_MAX_CHANNELS 1
80 #endif /* USE_SSH_EXTENDED */
81 
82 #ifdef USE_SSH
83 
84 /****************************************************************************
85 * *
86 * Utility Functions *
87 * *
88 ****************************************************************************/
89 
90 /* Check whether there are any active channels still present. Since a
91  channel can be half-closed (we've closed it for write but the other
92  side hasn't acknowledged the close yet) we allow the caller to specify
93  an excluded channel ID that's treated as logically closed for active
94  channel-check purposes even if a channel entry is still present for it.
95  This can also be used when closing channels to check whether this is the
96  last channel open, since closing the last channel also shuts down the
97  entire session */
98 
100 static BOOLEAN isChannelActive( const SESSION_INFO *sessionInfoPtr,
101  IN_INT_SHORT_Z const int excludedChannelID )
102  {
104  int iterationCount;
105 
106  assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
107 
108  REQUIRES_B( ( excludedChannelID == UNUSED_CHANNEL_ID ) || \
109  ( excludedChannelID > 0 && \
110  excludedChannelID < MAX_INTLENGTH_SHORT ) );
111 
112  for( attributeListPtr = sessionInfoPtr->attributeList, \
113  iterationCount = 0;
114  attributeListPtr != NULL && \
115  iterationCount < FAILSAFE_ITERATIONS_MAX;
116  attributeListPtr = attributeListPtr->next, iterationCount++ )
117  {
118  const SSH_CHANNEL_INFO *channelInfoPtr;
119 
120  /* If it's not an SSH channel, continue */
121  if( attributeListPtr->attributeID != CRYPT_SESSINFO_SSH_CHANNEL )
122  continue;
123 
124  /* It's an SSH channel, check whether it's the one that we're
125  after */
126  ENSURES( attributeListPtr->valueLength == sizeof( SSH_CHANNEL_INFO ) );
127  channelInfoPtr = attributeListPtr->value;
128  if( isActiveChannel( channelInfoPtr ) && \
129  channelInfoPtr->channelID != excludedChannelID )
130  return( TRUE );
131  }
132  ENSURES_B( iterationCount < FAILSAFE_ITERATIONS_MAX );
133 
134  return( FALSE );
135  }
136 
137 /* Helper function used to access SSH-specific internal attributes within
138  an attribute group (== single attribute-list item containing multiple
139  sub-items). Returns the attribute ID of the currently selected attribute
140  when attrGetType == ATTR_CURRENT, otherwise a boolean indicating whether
141  ATTR_PREV/ATTR_NEXT is still within the current subgroup */
142 
143 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
145  IN_ENUM_OPT( ATTR ) const ATTR_TYPE attrGetType,
146  OUT_INT_Z int *value )
147  {
148  static const CRYPT_ATTRIBUTE_TYPE attributeOrderList[] = {
152  CRYPT_ATTRIBUTE_NONE };
153  SSH_CHANNEL_INFO *channelInfoPtr = attributeListPtr->value;
154  CRYPT_ATTRIBUTE_TYPE attributeType = channelInfoPtr->cursorPos;
155  BOOLEAN doContinue;
156  int iterationCount;
157 
158  assert( isWritePtr( attributeListPtr, sizeof( ATTRIBUTE_LIST ) ) );
159  assert( isWritePtr( value, sizeof( int ) ) );
160 
161  REQUIRES( attrGetType >= ATTR_NONE && attrGetType < ATTR_LAST );
162 
163  /* Clear return value */
164  *value = 0;
165 
166  /* If we've just moved the cursor onto this attribute, reset the
167  position to the first internal attribute */
168  if( attributeListPtr->flags & ATTR_FLAG_CURSORMOVED )
169  {
170  attributeType = channelInfoPtr->cursorPos = \
171  CRYPT_SESSINFO_SSH_CHANNEL;
172  attributeListPtr->flags &= ~ATTR_FLAG_CURSORMOVED;
173  }
174 
175  /* If it's an information fetch, return the currently-selected
176  attribute */
177  if( attrGetType == ATTR_NONE )
178  {
179  *value = attributeType;
180  return( CRYPT_OK );
181  }
182 
183  for( doContinue = TRUE, iterationCount = 0;
184  doContinue && iterationCount < FAILSAFE_ITERATIONS_MED;
185  iterationCount++ )
186  {
187  int orderIndex;
188 
189  /* Find the position of the current sub-attribute in the attribute
190  order list and use that to get its successor/predecessor sub-
191  attribute */
192  for( orderIndex = 0;
193  attributeOrderList[ orderIndex ] != attributeType && \
194  attributeOrderList[ orderIndex ] != CRYPT_ATTRIBUTE_NONE && \
195  orderIndex < FAILSAFE_ARRAYSIZE( attributeOrderList, \
197  orderIndex++ );
198  ENSURES( orderIndex < FAILSAFE_ARRAYSIZE( attributeOrderList, \
200  if( attributeOrderList[ orderIndex ] == CRYPT_ATTRIBUTE_NONE )
201  {
202  /* We've reached the first/last sub-attribute within the current
203  item/group, tell the caller that there are no more sub-
204  attributes present and they have to move on to the next item/
205  group */
206  *value = FALSE;
207  return( CRYPT_OK );
208  }
209  if( attrGetType == ATTR_PREV )
210  {
211  attributeType = ( orderIndex <= 0 ) ? \
213  attributeOrderList[ orderIndex - 1 ];
214  }
215  else
216  attributeType = attributeOrderList[ orderIndex + 1 ];
217  if( attributeType == CRYPT_ATTRIBUTE_NONE )
218  {
219  /* We've reached the first/last sub-attribute within the current
220  item/group, exit as before */
221  *value = FALSE;
222  return( CRYPT_OK );
223  }
224 
225  /* Check whether the required sub-attribute is present. If not, we
226  continue and try the next one */
227  switch( attributeType )
228  {
232  doContinue = FALSE; /* Always present */
233  break;
234 
236  if( channelInfoPtr->arg1Len > 0 )
237  doContinue = FALSE;
238  break;
239 
241  if( channelInfoPtr->arg2Len > 0 )
242  doContinue = FALSE;
243  break;
244 
245  default:
246  retIntError();
247  }
248  }
249  ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
250  channelInfoPtr->cursorPos = attributeType;
251 
252  *value = TRUE;
253  return( CRYPT_OK );
254  }
255 
256 /****************************************************************************
257 * *
258 * Find Channel Information *
259 * *
260 ****************************************************************************/
261 
262 /* Find the attribute entry for a channel */
263 
265 static ATTRIBUTE_LIST *findChannelAttr( const SESSION_INFO *sessionInfoPtr,
266  IN const long channelNo )
267  {
269  int iterationCount;
270 
271  assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
272 
273  REQUIRES_N( ( channelNo == CRYPT_USE_DEFAULT ) || \
274  ( channelNo >= 0 && channelNo <= LONG_MAX ) );
275 
276  for( attributeListPtr = sessionInfoPtr->attributeList, \
277  iterationCount = 0;
278  attributeListPtr != NULL && \
279  iterationCount < FAILSAFE_ITERATIONS_MAX;
280  attributeListPtr = attributeListPtr->next, iterationCount++ )
281  {
282  const SSH_CHANNEL_INFO *channelInfoPtr;
283 
284  /* If it's not an SSH channel, continue */
285  if( attributeListPtr->attributeID != CRYPT_SESSINFO_SSH_CHANNEL )
286  continue;
287 
288  /* It's an SSH channel, check whether it's the one that we're
289  after */
290  ENSURES_N( attributeListPtr->valueLength == sizeof( SSH_CHANNEL_INFO ) );
291  channelInfoPtr = attributeListPtr->value;
292  if( channelNo == CRYPT_USE_DEFAULT )
293  {
294  /* We're looking for any open channel channel, return the first
295  match */
296  if( channelInfoPtr->flags & CHANNEL_FLAG_WRITECLOSED )
297  continue;
298  return( attributeListPtr );
299  }
300  if( channelInfoPtr->readChannelNo == channelNo || \
301  channelInfoPtr->writeChannelNo == channelNo )
302  return( attributeListPtr );
303  }
304  ENSURES_N( iterationCount < FAILSAFE_ITERATIONS_MAX );
305 
306  return( NULL );
307  }
308 
309 /* Find the SSH channel information for a channel, matching by channel
310  number, channel ID, and channel host + port information */
311 
313 static SSH_CHANNEL_INFO *findChannelByChannelNo( const SESSION_INFO *sessionInfoPtr,
314  IN const long channelNo )
315  {
316  const ATTRIBUTE_LIST *attributeListPtr = \
317  findChannelAttr( sessionInfoPtr, channelNo );
318 
319  assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
320 
321  REQUIRES_N( ( channelNo == CRYPT_USE_DEFAULT ) || \
322  ( channelNo >= 0 && channelNo <= LONG_MAX ) );
323 
324  return( ( attributeListPtr == NULL ) ? NULL : attributeListPtr->value );
325  }
326 
328 static SSH_CHANNEL_INFO *findChannelByID( const SESSION_INFO *sessionInfoPtr,
329  IN_INT_SHORT const int channelID )
330  {
332  int iterationCount;
333 
334  assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
335 
336  REQUIRES_N( channelID > 0 && channelID < MAX_INTLENGTH_SHORT );
337 
338  for( attributeListPtr = sessionInfoPtr->attributeList, \
339  iterationCount = 0;
340  attributeListPtr != NULL && \
341  iterationCount < FAILSAFE_ITERATIONS_MAX;
342  attributeListPtr = attributeListPtr->next, iterationCount++ )
343  {
344  const SSH_CHANNEL_INFO *channelInfoPtr;
345 
346  /* If it's not an SSH channel, continue */
347  if( attributeListPtr->attributeID != CRYPT_SESSINFO_SSH_CHANNEL )
348  continue;
349 
350  /* It's an SSH channel, check whether it's the that one we're
351  after */
352  ENSURES_N( attributeListPtr->valueLength == sizeof( SSH_CHANNEL_INFO ) );
353  channelInfoPtr = attributeListPtr->value;
354  if( channelInfoPtr->channelID == channelID )
355  return( ( SSH_CHANNEL_INFO * ) channelInfoPtr );
356  }
357  ENSURES_N( iterationCount < FAILSAFE_ITERATIONS_MAX );
358 
359  return( NULL );
360  }
361 
363 static SSH_CHANNEL_INFO *findChannelByAddr( const SESSION_INFO *sessionInfoPtr,
365  const char *addrInfo,
367  const int addrInfoLen )
368  {
370  int iterationCount;
371 
372  assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
373  assert( isReadPtr( addrInfo, addrInfoLen ) );
374 
375  REQUIRES_N( addrInfoLen > 0 && addrInfoLen < MAX_INTLENGTH_SHORT );
376 
377  for( attributeListPtr = sessionInfoPtr->attributeList, \
378  iterationCount = 0;
379  attributeListPtr != NULL && \
380  iterationCount < FAILSAFE_ITERATIONS_MAX;
381  attributeListPtr = attributeListPtr->next, iterationCount++ )
382  {
383  const SSH_CHANNEL_INFO *channelInfoPtr;
384 
385  /* If it's not an SSH channel, continue */
386  if( attributeListPtr->attributeID != CRYPT_SESSINFO_SSH_CHANNEL )
387  continue;
388 
389  /* It's an SSH channel, check whether it's the one that we're
390  after */
391  ENSURES_N( attributeListPtr->valueLength == sizeof( SSH_CHANNEL_INFO ) );
392  channelInfoPtr = attributeListPtr->value;
393  if( channelInfoPtr->arg1Len == addrInfoLen && \
394  !memcmp( channelInfoPtr->arg1, addrInfo, addrInfoLen ) )
395  return( ( SSH_CHANNEL_INFO * ) channelInfoPtr );
396  }
397  ENSURES_N( iterationCount < FAILSAFE_ITERATIONS_MAX );
398 
399  return( NULL );
400  }
401 
403 static const SSH_CHANNEL_INFO *getCurrentChannelInfo( const SESSION_INFO *sessionInfoPtr,
404  IN_ENUM( CHANNEL ) \
405  const CHANNEL_TYPE channelType )
406  {
407  static const SSH_CHANNEL_INFO nullChannel = \
410  SSH_INFO *sshInfo = sessionInfoPtr->sessionSSH;
411  const SSH_CHANNEL_INFO *channelInfoPtr;
412  const int channelID = ( channelType == CHANNEL_READ ) ? \
413  sshInfo->currReadChannel : \
414  sshInfo->currWriteChannel;
415 
416  assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
417 
418  REQUIRES_N( channelType > CHANNEL_NONE && \
419  channelType < CHANNEL_LAST );
420 
421  /* If there's no channel open yet, return the null channel */
422  if( channelID == UNUSED_CHANNEL_ID )
423  return( ( SSH_CHANNEL_INFO * ) &nullChannel );
424 
425  channelInfoPtr = findChannelByID( sessionInfoPtr,
426  ( channelType == CHANNEL_READ ) ? \
427  sshInfo->currReadChannel : \
428  sshInfo->currWriteChannel );
429  return( ( channelInfoPtr == NULL ) ? \
430  ( SSH_CHANNEL_INFO * ) &nullChannel : channelInfoPtr );
431  }
432 
433 /****************************************************************************
434 * *
435 * Get/Set Channel Information *
436 * *
437 ****************************************************************************/
438 
439 /* Get the currently active channel */
440 
441 CHECK_RETVAL_RANGE( 1, LONG_MAX ) STDC_NONNULL_ARG( ( 1 ) ) \
442 long getCurrentChannelNo( const SESSION_INFO *sessionInfoPtr,
443  IN_ENUM( CHANNEL ) const CHANNEL_TYPE channelType )
444  {
445  const SSH_CHANNEL_INFO *channelInfoPtr = \
446  getCurrentChannelInfo( sessionInfoPtr, channelType );
447 
448  assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
449 
450  REQUIRES( channelType == CHANNEL_READ || channelType == CHANNEL_WRITE );
451  REQUIRES( channelInfoPtr != NULL );
452 
453  return( ( channelType == CHANNEL_READ ) ? \
454  channelInfoPtr->readChannelNo : channelInfoPtr->writeChannelNo );
455  }
456 
457 /* Get/set an attribute or SSH-specific internal attribute from/for the
458  current channel */
459 
461 int getChannelAttribute( const SESSION_INFO *sessionInfoPtr,
463  OUT_INT_Z int *value )
464  {
465  const SSH_CHANNEL_INFO *channelInfoPtr = \
466  getCurrentChannelInfo( sessionInfoPtr, CHANNEL_READ );
467 
468  assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
469  assert( isWritePtr( value, sizeof( int ) ) );
470 
471  REQUIRES( isAttribute( attribute ) );
472  REQUIRES( channelInfoPtr != NULL );
473 
474  /* Clear return values */
475  *value = 0;
476 
477  if( isNullChannel( channelInfoPtr ) )
478  return( CRYPT_ERROR_NOTFOUND );
479 
480  switch( attribute )
481  {
483  *value = channelInfoPtr->channelID;
484  return( CRYPT_OK );
485 
487  *value = isActiveChannel( channelInfoPtr ) ? TRUE : FALSE;
488  return( CRYPT_OK );
489  }
490 
491  retIntError();
492  }
493 
495 int getChannelAttributeS( const SESSION_INFO *sessionInfoPtr,
496  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attribute,
498  void *data,
499  IN_LENGTH_SHORT_Z const int dataMaxLength,
501  {
502  const SSH_CHANNEL_INFO *channelInfoPtr = \
503  getCurrentChannelInfo( sessionInfoPtr, CHANNEL_READ );
504 
505  assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
506  assert( ( data == NULL && dataMaxLength == 0 ) || \
507  isWritePtr( data, dataMaxLength ) );
508  assert( isWritePtr( dataLength, sizeof( int ) ) );
509 
510  REQUIRES( isAttribute( attribute ) );
511  REQUIRES( ( data == NULL && dataMaxLength == 0 ) || \
512  ( data != NULL && \
513  dataMaxLength > 0 && \
514  dataMaxLength < MAX_INTLENGTH_SHORT ) );
515  REQUIRES( channelInfoPtr != NULL );
516 
517  /* Clear return values */
518  if( data != NULL )
519  memset( data, 0, min( 16, dataMaxLength ) );
520  *dataLength = 0;
521 
522  if( isNullChannel( channelInfoPtr ) )
523  return( CRYPT_ERROR_NOTFOUND );
524 
525  switch( attribute )
526  {
528  return( attributeCopyParams( data, dataMaxLength, dataLength,
529  channelInfoPtr->type,
530  channelInfoPtr->typeLen ) );
531 
533  return( attributeCopyParams( data, dataMaxLength, dataLength,
534  channelInfoPtr->arg1,
535  channelInfoPtr->arg1Len ) );
536 
538  return( attributeCopyParams( data, dataMaxLength, dataLength,
539  channelInfoPtr->arg2,
540  channelInfoPtr->arg2Len ) );
541  }
542 
543  retIntError();
544  }
545 
547 int getChannelExtAttribute( const SESSION_INFO *sessionInfoPtr,
548  IN_ENUM( SSH_ATTRIBUTE ) \
549  const SSH_ATTRIBUTE_TYPE attribute,
550  OUT_INT_Z int *value )
551  {
552  const SSH_CHANNEL_INFO *channelInfoPtr = \
553  getCurrentChannelInfo( sessionInfoPtr, CHANNEL_READ );
554 
555  assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
556  assert( isWritePtr( value, sizeof( int ) ) );
557 
558  REQUIRES( isAttribute( attribute ) );
559  REQUIRES( channelInfoPtr != NULL );
560 
561  /* Clear return value */
562  *value = 0;
563 
564  if( isNullChannel( channelInfoPtr ) )
565  return( CRYPT_ERROR_NOTFOUND );
566 
567  switch( attribute )
568  {
570  *value = channelInfoPtr->windowCount;
571  return( CRYPT_OK );
572 
574  *value = channelInfoPtr->windowSize;
575  return( CRYPT_OK );
576  }
577 
578  retIntError();
579  }
580 
582 int setChannelAttribute( INOUT SESSION_INFO *sessionInfoPtr,
583  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attribute,
584  IN_INT_SHORT const int value )
585  {
586  SSH_CHANNEL_INFO *channelInfoPtr;
587 
588  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
589 
590  REQUIRES( isAttribute( attribute ) );
591  REQUIRES( value > 0 && value < MAX_INTLENGTH_SHORT );
592 
593  /* If we're setting the channel ID this doesn't change any channel
594  attribute but selects the one with the given ID */
595  if( attribute == CRYPT_SESSINFO_SSH_CHANNEL )
596  {
597  channelInfoPtr = findChannelByID( sessionInfoPtr, value );
598  if( channelInfoPtr == NULL )
599  return( CRYPT_ERROR_NOTFOUND );
600  return( selectChannel( sessionInfoPtr, channelInfoPtr->writeChannelNo,
601  CHANNEL_WRITE ) );
602  }
603 
604  retIntError();
605  }
606 
607 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
608 int setChannelAttributeS( INOUT SESSION_INFO *sessionInfoPtr,
609  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attribute,
610  IN_BUFFER( dataLength ) const void *data,
611  IN_RANGE( 1, CRYPT_MAX_TEXTSIZE ) const int dataLength )
612  {
613  SSH_CHANNEL_INFO *channelInfoPtr;
614 
615  assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
616  assert( isReadPtr( data, dataLength ) );
617 
618  REQUIRES( isAttribute( attribute ) );
619  REQUIRES( dataLength > 0 && dataLength <= CRYPT_MAX_TEXTSIZE );
620 
621  /* Set the attribute for the currently-active channel */
622  channelInfoPtr = ( SSH_CHANNEL_INFO * ) \
623  getCurrentChannelInfo( sessionInfoPtr, CHANNEL_READ );
624  REQUIRES( channelInfoPtr != NULL );
625  if( isNullChannel( channelInfoPtr ) )
626  return( CRYPT_ERROR_NOTFOUND );
627  switch( attribute )
628  {
630  return( attributeCopyParams( channelInfoPtr->type,
632  &channelInfoPtr->typeLen,
633  data, dataLength ) );
634 
636  return( attributeCopyParams( channelInfoPtr->arg1,
638  &channelInfoPtr->arg1Len,
639  data, dataLength ) );
640 
642  return( attributeCopyParams( channelInfoPtr->arg2,
644  &channelInfoPtr->arg2Len,
645  data, dataLength ) );
646  }
647 
648  retIntError();
649  }
650 
652 int setChannelExtAttribute( const SESSION_INFO *sessionInfoPtr,
653  IN_ATTRIBUTE const SSH_ATTRIBUTE_TYPE attribute,
654  IN_INT_Z const int value )
655  {
656  SSH_CHANNEL_INFO *channelInfoPtr = ( SSH_CHANNEL_INFO * ) \
657  getCurrentChannelInfo( sessionInfoPtr, CHANNEL_READ );
658 
659  assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
660 
661  REQUIRES( ( attribute == SSH_ATTRIBUTE_ACTIVE && value == TRUE ) || \
662  ( attribute != SSH_ATTRIBUTE_ACTIVE && \
663  value >= 0 && value < INT_MAX ) );
664  REQUIRES( channelInfoPtr != NULL );
665 
666  if( isNullChannel( channelInfoPtr ) )
667  return( CRYPT_ERROR_NOTFOUND );
668 
669  switch( attribute )
670  {
672  channelInfoPtr->flags |= CHANNEL_FLAG_ACTIVE;
673  return( CRYPT_OK );
674 
676  channelInfoPtr->windowCount = value;
677  return( CRYPT_OK );
678 
680  channelInfoPtr->windowSize = value;
681  return( CRYPT_OK );
682 
684  channelInfoPtr->writeChannelNo = value;
685  return( CRYPT_OK );
686  }
687 
688  retIntError();
689  }
690 
691 /* Get the status of a channel: Not open, read-side open/write-side closed,
692  open */
693 
694 CHECK_RETVAL_ENUM( CHANNEL ) STDC_NONNULL_ARG( ( 1 ) ) \
695 CHANNEL_TYPE getChannelStatusByChannelNo( const SESSION_INFO *sessionInfoPtr,
696  IN const long channelNo )
697  {
698  SSH_CHANNEL_INFO *channelInfoPtr;
699 
700  assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
701 
702  REQUIRES_EXT( ( channelNo >= 0 && channelNo <= LONG_MAX ), \
703  CHANNEL_NONE );
704 
705  channelInfoPtr = findChannelByChannelNo( sessionInfoPtr, channelNo );
706  return( ( channelInfoPtr == NULL ) ? CHANNEL_NONE : \
707  ( channelInfoPtr->flags & CHANNEL_FLAG_WRITECLOSED ) ? \
709  }
710 
711 CHECK_RETVAL_ENUM( CHANNEL ) STDC_NONNULL_ARG( ( 1 ) ) \
712 CHANNEL_TYPE getChannelStatusByAddr( const SESSION_INFO *sessionInfoPtr,
713  IN_BUFFER( addrInfoLen ) const char *addrInfo,
714  IN_LENGTH_SHORT const int addrInfoLen )
715  {
716  const SSH_CHANNEL_INFO *channelInfoPtr;
717 
718  assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
719  assert( isReadPtr( addrInfo, addrInfoLen ) );
720 
721  REQUIRES_EXT( ( addrInfoLen > 0 && addrInfoLen < MAX_INTLENGTH_SHORT ), \
722  CHANNEL_NONE );
723 
724  channelInfoPtr = findChannelByAddr( sessionInfoPtr, addrInfo,
725  addrInfoLen );
726  return( ( channelInfoPtr == NULL ) ? CHANNEL_NONE : \
727  ( channelInfoPtr->flags & CHANNEL_FLAG_WRITECLOSED ) ? \
729  }
730 
731 /****************************************************************************
732 * *
733 * Channel Management Functions *
734 * *
735 ****************************************************************************/
736 
737 /* Select a channel */
738 
740 int selectChannel( INOUT SESSION_INFO *sessionInfoPtr,
741  IN const long channelNo,
742  IN_ENUM_OPT( CHANNEL ) const CHANNEL_TYPE channelType )
743  {
744  SSH_INFO *sshInfo = sessionInfoPtr->sessionSSH;
745  SSH_CHANNEL_INFO *channelInfoPtr;
746 
747  assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
748 
749  REQUIRES( ( channelNo == CRYPT_USE_DEFAULT ) || \
750  ( channelNo >= 0 && channelNo <= LONG_MAX ) );
751  /* CRYPT_USE_DEFAULT is used to select the first available
752  channel, used when closing all channels in a loop */
753  REQUIRES( ( channelType == CHANNEL_NONE ) || \
754  ( channelType > CHANNEL_NONE && channelType < CHANNEL_LAST ) );
755  /* We allow CHANNEL_NONE to allow selection of created-but-not-
756  yet-active channels */
757 
758  /* Locate the channel and update the current channel information. We
759  allow a special channel-type indicator of CHANNEL_NONE to specify the
760  selection of not-yet-activated channels. Since it's possible to have
761  per-channel packet sizes we also update the overall packet size
762  value */
763  channelInfoPtr = findChannelByChannelNo( sessionInfoPtr, channelNo );
764  if( channelInfoPtr == NULL )
765  return( CRYPT_ERROR_NOTFOUND );
766  if( !isActiveChannel( channelInfoPtr ) && channelType != CHANNEL_NONE )
767  return( CRYPT_ERROR_NOTINITED );
768  switch( channelType )
769  {
770  case CHANNEL_READ:
771  sshInfo->currReadChannel = channelInfoPtr->channelID;
772  break;
773 
774  case CHANNEL_WRITE:
775  sshInfo->currWriteChannel = channelInfoPtr->channelID;
776  break;
777 
778  case CHANNEL_BOTH:
779  case CHANNEL_NONE:
780  sshInfo->currReadChannel = \
781  sshInfo->currWriteChannel = channelInfoPtr->channelID;
782  break;
783 
784  default:
785  retIntError();
786  }
787  sessionInfoPtr->maxPacketSize = channelInfoPtr->maxPacketSize;
788 
789  return( CRYPT_OK );
790  }
791 
792 /* Add/create/delete a channel */
793 
794 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 4 ) ) \
795 int addChannel( INOUT SESSION_INFO *sessionInfoPtr,
796  IN const long channelNo,
797  IN_LENGTH_MIN( 1024 ) const int maxPacketSize,
798  IN_BUFFER( typeLen ) const void *type,
799  IN_LENGTH_SHORT const int typeLen,
800  IN_BUFFER_OPT( arg1Len ) const void *arg1,
801  IN_LENGTH_SHORT const int arg1Len )
802  {
804  SSH_INFO *sshInfo = sessionInfoPtr->sessionSSH;
805  SSH_CHANNEL_INFO channelInfo;
806  int channelCount, iterationCount, status;
807 
808  assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
809  assert( isReadPtr( type, typeLen ) );
810  assert( ( arg1 == NULL && arg1Len == 0 ) ||
811  isReadPtr( arg1, arg1Len ) );
812 
813  REQUIRES( channelNo >= 0 && channelNo <= LONG_MAX );
814  REQUIRES( maxPacketSize >= 1024 && maxPacketSize < MAX_INTLENGTH );
815  REQUIRES( typeLen > 0 && typeLen < MAX_INTLENGTH_SHORT );
816  REQUIRES( ( arg1 == NULL && arg1Len == 0 ) || \
817  ( arg1 != NULL && \
818  arg1Len > 0 && arg1Len < MAX_INTLENGTH_SHORT ) );
819 
820  /* Make sure that this channel doesn't already exist */
821  if( findChannelByChannelNo( sessionInfoPtr, channelNo ) != NULL )
822  {
825  "Attempt to add duplicate channel %lX", channelNo ) );
826  }
827 
828  /* SSH channels are allocated unique IDs for tracking by cryptlib,
829  since (at least in theory) the SSH-level channel IDs may repeat.
830  If the initial (not-yet-initialised) channel ID matches the
831  UNUSED_CHANNEL_ID magic value we initialise it to one past that
832  value */
833  if( sshInfo->channelIndex <= UNUSED_CHANNEL_ID )
834  sshInfo->channelIndex = UNUSED_CHANNEL_ID + 1;
835 
836  /* Make sure that we haven't exceeded the maximum number of channels */
837  for( channelCount = 0, \
838  attributeListPtr = sessionInfoPtr->attributeList, \
839  iterationCount = 0;
840  attributeListPtr != NULL && \
841  iterationCount < FAILSAFE_ITERATIONS_MAX;
842  attributeListPtr = attributeListPtr->next, iterationCount++ )
843  {
844  if( attributeListPtr->attributeID == CRYPT_SESSINFO_SSH_CHANNEL )
845  channelCount++;
846  }
847  ENSURES( iterationCount < FAILSAFE_ITERATIONS_MAX );
848  if( channelCount > SSH_MAX_CHANNELS )
849  {
852  "Maximum number (%d) of SSH channels reached",
853  SSH_MAX_CHANNELS ) );
854  }
855 
856  /* Initialise the information for the new channel and create it */
857  memset( &channelInfo, 0, sizeof( SSH_CHANNEL_INFO ) );
858  channelInfo.channelID = sshInfo->channelIndex++;
859  channelInfo.readChannelNo = channelInfo.writeChannelNo = channelNo;
860  channelInfo.maxPacketSize = maxPacketSize;
861  status = attributeCopyParams( channelInfo.type, CRYPT_MAX_TEXTSIZE,
862  &channelInfo.typeLen, type, typeLen );
863  if( cryptStatusOK( status ) && arg1 != NULL )
864  status = attributeCopyParams( channelInfo.arg1, CRYPT_MAX_TEXTSIZE,
865  &channelInfo.arg1Len, arg1, arg1Len );
866  if( cryptStatusOK( status ) )
867  {
868  status = addSessionInfoComposite( &sessionInfoPtr->attributeList,
870  accessFunction, &channelInfo,
871  sizeof( SSH_CHANNEL_INFO ),
874  }
875  if( cryptStatusError( status ) )
876  return( status );
877 
878  /* Select the newly-created channel. We have to select it using the
879  special-case indicator of CHANNEL_NONE since we can't normally
880  select an inactive channel */
881  return( selectChannel( sessionInfoPtr, channelNo, CHANNEL_NONE ) );
882  }
883 
885 int createChannel( INOUT SESSION_INFO *sessionInfoPtr )
886  {
887  SSH_INFO *sshInfo = sessionInfoPtr->sessionSSH;
888  int iterationCount;
889 
890  assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
891 
892  /* Find an unused channel number. Since the peer can request the
893  creation of arbitrary-numbered channels we have to be careful to
894  ensure that we don't clash with any existing peer-requested channel
895  numbers when we create our own one */
896  for( iterationCount = 0;
897  findChannelByChannelNo( sessionInfoPtr, \
898  sshInfo->nextChannelNo ) != NULL && \
899  iterationCount < FAILSAFE_ITERATIONS_MED;
900  iterationCount++ )
901  {
902  /* This channel number is already in use, move on to the next one */
903  sshInfo->nextChannelNo++;
904  }
905  ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
906 
907  /* Create a channel with the new channel number */
908  return( addChannel( sessionInfoPtr, sshInfo->nextChannelNo++,
909  sessionInfoPtr->sendBufSize - EXTRA_PACKET_SIZE,
910  "session", 7, NULL, 0 ) );
911  }
912 
914 int deleteChannel( INOUT SESSION_INFO *sessionInfoPtr,
915  IN const long channelNo,
916  IN_ENUM( CHANNEL ) const CHANNEL_TYPE channelType,
917  const BOOLEAN deleteLastChannel )
918  {
919  SSH_INFO *sshInfo = sessionInfoPtr->sessionSSH;
920  SSH_CHANNEL_INFO *channelInfoPtr;
922  int channelID;
923 
924  assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
925 
926  REQUIRES( channelNo >= 0 && channelNo <= LONG_MAX );
927  REQUIRES( channelType > CHANNEL_NONE && channelType < CHANNEL_LAST );
928 
929  /* Locate the channel information */
930  attributeListPtr = findChannelAttr( sessionInfoPtr, channelNo );
931  if( attributeListPtr == NULL )
932  return( isChannelActive( sessionInfoPtr, UNUSED_CHANNEL_ID ) ? \
934  channelInfoPtr = attributeListPtr->value;
935  channelID = channelInfoPtr->channelID;
936 
937  /* If we can't delete the last remaining channel (it has to be done
938  explicitly via a session close) and there are no active channels
939  left besides the current one then we can't do anything */
940  if( !deleteLastChannel && \
941  !isChannelActive( sessionInfoPtr, channelID ) )
942  return( CRYPT_ERROR_PERMISSION );
943 
944  /* Delete the channel entry. If we're only closing the write side we
945  mark the channel as closed for write but leave the overall channel
946  open */
947  if( channelType == CHANNEL_WRITE )
948  {
949  REQUIRES( !( channelInfoPtr->flags & CHANNEL_FLAG_WRITECLOSED ) );
950  channelInfoPtr->flags |= CHANNEL_FLAG_WRITECLOSED;
951  if( channelID == sshInfo->currWriteChannel )
953  return( isChannelActive( sessionInfoPtr, \
954  channelInfoPtr->channelID ) ? \
955  CRYPT_OK : OK_SPECIAL );
956  }
957  deleteSessionInfo( &sessionInfoPtr->attributeList,
958  &sessionInfoPtr->attributeListCurrent,
959  attributeListPtr );
960 
961  /* If we've deleted the current channel, select a null channel until a
962  new one is created/selected */
963  if( channelID == sshInfo->currReadChannel )
965  if( channelID == sshInfo->currWriteChannel )
967 
968  /* We've deleted an open channel, check if there are any channels left
969  and if not let the caller know */
970  return( isChannelActive( sessionInfoPtr, UNUSED_CHANNEL_ID ) ? \
971  CRYPT_OK : OK_SPECIAL );
972  }
973 
974 #if 0
975 
976 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
977 int deleteChannelByAddr( INOUT SESSION_INFO *sessionInfoPtr,
978  IN_BUFFER( addrInfoLen ) const char *addrInfo,
979  IN_LENGTH_SHORT const int addrInfoLen )
980  {
981  const SSH_CHANNEL_INFO *channelInfoPtr;
982 
983  assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
984  assert( isReadPtr( addrInfo, addrInfoLen ) );
985 
986  REQUIRES( addrInfoLen > 0 && addrInfoLen < MAX_INTLENGTH_SHORT );
987 
988  channelInfoPtr = findChannelByAddr( sessionInfoPtr, addrInfo,
989  addrInfoLen );
990  if( channelInfoPtr == NULL )
991  return( CRYPT_ERROR_NOTFOUND );
992 
993  /* We've found the entry that it corresponds to, clear it. This doesn't
994  actually delete the entire channel but merely deletes the forwarding.
995  See the note in ssh2_msg.c for why this is currently unused */
996  memset( channelInfoPtr->arg1, 0, CRYPT_MAX_TEXTSIZE );
997  channelInfoPtr->arg1Len = 0;
998  return( CRYPT_OK );
999  }
1000 #endif /* 0 */
1001 
1002 /****************************************************************************
1003 * *
1004 * Enqueue/Send Channel Messages *
1005 * *
1006 ****************************************************************************/
1007 
1008 /* Enqueue a response to a request, to be sent at the next available
1009  opportunity. This is required because we may be in the middle of
1010  assembling or sending a data packet when we need to send the response
1011  so the response has to be deferred until after the data packet has been
1012  completed and sent */
1013 
1014 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
1015 int enqueueResponse( INOUT SESSION_INFO *sessionInfoPtr,
1016  IN_RANGE( 1, 255 ) const int type,
1017  IN_RANGE( 0, 4 ) const int noParams,
1018  IN const long channelNo,
1019  const int param1, const int param2, const int param3 )
1020  {
1021  SSH_RESPONSE_INFO *respPtr = &sessionInfoPtr->sessionSSH->response;
1022  STREAM stream;
1023  int status = CRYPT_OK;
1024 
1025  assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
1026 
1027  REQUIRES( type > 0 && type <= 0xFF );
1028  REQUIRES( noParams >= 0 && noParams <= 4 );
1029  /* channelNo is the first parameter */
1030  REQUIRES( channelNo >= 0 && channelNo <= LONG_MAX );
1031 
1032  /* If there's already a response enqueued we can't enqueue another one
1033  until it's been sent */
1034  REQUIRES( respPtr->type == 0 );
1035 
1036  respPtr->type = type;
1037  sMemOpen( &stream, respPtr->data, SSH_MAX_RESPONSESIZE );
1038  if( noParams > 0 )
1039  status = writeUint32( &stream, channelNo );
1040  if( noParams > 1 )
1041  status = writeUint32( &stream, param1 );
1042  if( noParams > 2 )
1043  status = writeUint32( &stream, param2 );
1044  if( noParams > 3 )
1045  status = writeUint32( &stream, param3 );
1046  ENSURES( cryptStatusOK( status ) );
1047  respPtr->dataLen = stell( &stream );
1048  sMemDisconnect( &stream );
1049 
1050  return( CRYPT_OK );
1051  }
1052 
1053 /* Assemble a packet for and send a previously enqueued response. This
1054  potentially appends a control packet after the end of an existing payload
1055  packet so the buffer indicator used is sendBufSize rather than
1056  maxPacketSize, since we may already have maxPacketSize bytes worth of
1057  payload data present.
1058 
1059  This can be called in one of two ways, if called as appendChannelData()
1060  then it's being piggybacked onto the end of existing data at a location
1061  specified by the 'offset' parameter and we assemble the packet at that
1062  point but it'll be sent as part of the main packet send. If called as
1063  enqueueChannelData() or sendEnqueuedResponse() then we have the send
1064  buffer to ourselves (offset == CRYPT_UNUSED) and can assemble and send it
1065  immediately */
1066 
1067 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
1068 static int encodeSendResponse( INOUT SESSION_INFO *sessionInfoPtr,
1069  IN_LENGTH_OPT const int offset,
1070  OUT_OPT_LENGTH_Z int *responseSize )
1071  {
1072  SSH_RESPONSE_INFO *respPtr = &sessionInfoPtr->sessionSSH->response;
1073  STREAM stream;
1074  const BOOLEAN assembleOnly = ( offset != CRYPT_UNUSED ) ? TRUE : FALSE;
1075  BOOLEAN adjustedStartOffset = FALSE;
1076  int sendBufOffset = assembleOnly ? offset : sessionInfoPtr->sendBufPos;
1077  int encodedResponseSize = DUMMY_INIT, dummy, status;
1078 
1079  assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
1080  assert( responseSize == NULL || \
1081  isWritePtr( responseSize, sizeof( int ) ) );
1082 
1083  REQUIRES( ( offset == CRYPT_UNUSED && responseSize == NULL ) || \
1084  ( offset >= 0 && offset < sessionInfoPtr->sendBufSize && \
1085  responseSize != NULL ) );
1086  REQUIRES( sendBufOffset >= 0 && offset < sessionInfoPtr->sendBufSize );
1087 
1088  /* Make sure that there's room for at least two packets worth of
1089  wrappers plus a short control packet, needed to handle a control
1090  packet piggybacked onto the end of a data packet. The reason for the
1091  doubling of the IV count is because the minimum padding length
1092  requirement can result in an expansion by two encrypted blocks rather
1093  than one */
1095  ( 2 * ( SSH2_HEADER_SIZE + CRYPT_MAX_HASHSIZE + \
1096  ( 2 * CRYPT_MAX_IVSIZE ) ) ) + 32,
1097  "Buffer packet size" );
1098 
1099  /* Clear return value */
1100  if( responseSize != NULL )
1101  *responseSize = 0;
1102 
1103  /* If there's an incomplete packet in the process of being assembled in
1104  the send buffer then we can't do anything. If we're just assembling
1105  a response to append to a completed packet then we know that the
1106  packet that's present is a complete one so we skip this check */
1107  if( assembleOnly && !sessionInfoPtr->partialWrite && \
1108  ( sendBufOffset > sessionInfoPtr->sendBufStartOfs ) )
1109  return( CRYPT_OK );
1110 
1111  /* The send buffer is allocated to always allow the piggybacking of one
1112  packet of control data */
1113  ENSURES( sendBufOffset + ( SSH2_HEADER_SIZE + 16 + respPtr->dataLen + \
1115  sessionInfoPtr->sendBufSize );
1116 
1117  ENSURES( ( sendBufOffset <= sessionInfoPtr->sendBufStartOfs ) || \
1118  ( sessionInfoPtr->partialWrite && \
1119  sendBufOffset + ( SSH2_HEADER_SIZE + 16 + respPtr->dataLen + \
1121  sessionInfoPtr->sendBufSize ) );
1122 
1123  /* If we're in the data transfer phase and there's nothing in the send
1124  buffer, set the packet start offset to zero. We have to do this
1125  because it's pre-adjusted to accomodate the header for a payload data
1126  packet, since we're assembling our own packet in the buffer there's
1127  no need for this additional header room */
1128  if( ( sessionInfoPtr->flags & SESSION_ISOPEN ) && \
1129  sendBufOffset == sessionInfoPtr->sendBufStartOfs )
1130  {
1131  sendBufOffset = 0;
1132  adjustedStartOffset = TRUE;
1133  }
1134 
1135  /* Assemble the response as a new packet at the end of any existing
1136  data */
1137  REQUIRES( rangeCheckZ( sendBufOffset,
1138  sessionInfoPtr->sendBufSize - sendBufOffset,
1139  sessionInfoPtr->sendBufSize ) );
1140  sMemOpen( &stream, sessionInfoPtr->sendBuffer + sendBufOffset,
1141  sessionInfoPtr->sendBufSize - sendBufOffset );
1142  swrite( &stream, "\x00\x00\x00\x00\x00", SSH2_HEADER_SIZE );
1143  status = sputc( &stream, respPtr->type );
1144  if( respPtr->dataLen > 0 )
1145  {
1146  /* Some responses can consist purely of an ID byte */
1147  status = swrite( &stream, respPtr->data, respPtr->dataLen );
1148  }
1149  if( cryptStatusOK( status ) )
1150  status = wrapPacketSSH2( sessionInfoPtr, &stream, 0, FALSE, TRUE );
1151  if( cryptStatusOK( status ) )
1152  encodedResponseSize = stell( &stream );
1153  if( cryptStatusError( status ) )
1154  {
1155  sMemDisconnect( &stream );
1156  return( status );
1157  }
1158 
1159  /* We've sent (or at least assembled) the response, clear the enqueued
1160  data */
1161  memset( respPtr, 0, sizeof( SSH_RESPONSE_INFO ) );
1162 
1163  /* If we're only assembling the data and the caller is taking care of
1164  sending the assembled packet, we're done */
1165  if( assembleOnly )
1166  {
1167  sMemDisconnect( &stream );
1168  *responseSize = encodedResponseSize;
1169  return( CRYPT_OK );
1170  }
1171 
1172  /* If we're still in the handshake phase (so this is part of the initial
1173  session negotiation, for example a response to a global or channel
1174  request) then we need to send the packet directly to avoid messing
1175  up the send buffering */
1176  if( !( sessionInfoPtr->flags & SESSION_ISOPEN ) )
1177  {
1178  status = sendPacketSSH2( sessionInfoPtr, &stream, TRUE );
1179  sMemDisconnect( &stream );
1180  return( status );
1181  }
1182 
1183  /* Write the response, using the standard data-flush mechanism to try
1184  and get the data out. We set the partial-write flag because what
1185  we've just added is pre-packaged data that doesn't have to go through
1186  the data-payload encoding process */
1187  sMemDisconnect( &stream );
1188  if( adjustedStartOffset )
1189  {
1190  /* We're in the data transfer phase, in which case the buffer
1191  position is offset into the send buffer to leave room for the
1192  packet header. Since we're adding our own header we've started
1193  the packet at the start of the send buffer, i.e. with
1194  sendBufPos = 0 rather than sendBufPos = sendBufStartOffset, so we
1195  set the new position to the total size of the data written rather
1196  than adding it to the existing value */
1197  sessionInfoPtr->sendBufPos = encodedResponseSize;
1198  }
1199  else
1200  {
1201  assert( 0 ); /* When does this occur? */
1202  sessionInfoPtr->sendBufPos += encodedResponseSize;
1203  }
1204  sessionInfoPtr->partialWrite = TRUE;
1205  return( putSessionData( sessionInfoPtr, NULL, 0, &dummy ) );
1206  }
1207 
1208 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
1209 int sendEnqueuedResponse( INOUT SESSION_INFO *sessionInfoPtr )
1210  {
1211  assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
1212 
1213  return( encodeSendResponse( sessionInfoPtr, CRYPT_UNUSED, NULL ) );
1214  }
1215 
1216 /* Enqueue channel control data ready to be sent, and try and send it if
1217  possible. This is used to send window-adjust messages for the SSH
1218  performance handbrake by first enqueueing the window adjust and then,
1219  if the send buffer is available, sending it. If it's not available
1220  then it'll be piggybacked onto the channel payload data later on when
1221  it's being sent via appendChannelData() below */
1222 
1223 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
1224 int enqueueChannelData( INOUT SESSION_INFO *sessionInfoPtr,
1225  IN_RANGE( 1, 255 ) const int type,
1226  IN const long channelNo,
1227  const int param )
1228  {
1229  int status;
1230 
1231  assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
1232 
1233  REQUIRES( type > 0 && type <= 0xFF );
1234  REQUIRES( channelNo >= 0 && channelNo <= LONG_MAX );
1235 
1236  status = enqueueResponse( sessionInfoPtr, type, 2, channelNo, param,
1238  if( cryptStatusError( status ) )
1239  return( status );
1240  return( encodeSendResponse( sessionInfoPtr, CRYPT_UNUSED, NULL ) );
1241  }
1242 
1243 /* Append enqueued channel control data to existing channel payload data
1244  without trying to send it. In this case the control data send is being
1245  piggybacked on a payload data send and will be handled by the caller,
1246  with the control flow on the caller side being:
1247 
1248  preparepacketFunction:
1249  wrap channel data;
1250  if( enqueued control data present )
1251  appendChannelData();
1252  send wrapped channel data and wrapped control data */
1253 
1254 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
1255 int appendChannelData( INOUT SESSION_INFO *sessionInfoPtr,
1256  IN_LENGTH_SHORT_Z const int offset )
1257  {
1258  int channelDataSize, status;
1259 
1260  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
1261 
1262  REQUIRES( offset >= 0 && offset < sessionInfoPtr->sendBufSize );
1263 
1264  status = encodeSendResponse( sessionInfoPtr, offset, &channelDataSize );
1265  return( cryptStatusError( status ) ? status : channelDataSize );
1266  }
1267 #endif /* USE_SSH */