📄 ssh2_chn.c
字号:
/****************************************************************************
* *
* cryptlib SSHv2 Channel Management *
* Copyright Peter Gutmann 1998-2005 *
* *
****************************************************************************/
#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL )
#include "crypt.h"
#include "misc_rw.h"
#include "session.h"
#include "ssh.h"
#elif defined( INC_CHILD )
#include "../crypt.h"
#include "../misc/misc_rw.h"
#include "session.h"
#include "ssh.h"
#else
#include "crypt.h"
#include "misc/misc_rw.h"
#include "session/session.h"
#include "session/ssh.h"
#endif /* Compiler-specific includes */
/* Channel flags */
#define CHANNEL_FLAG_NONE 0x00 /* No channel flag */
#define CHANNEL_FLAG_ACTIVE 0x01 /* Channel is active */
#define CHANNEL_FLAG_WRITECLOSED 0x02 /* Write-side of ch.closed */
/* Per-channel information. SSH channel IDs are 32-bit/4 byte data values
and can be reused during sessions so we provide our own guaranteed-unique
short int ID for users to identify a particular channel. Since each
channel can have its own distinct characteristics, we have to record
information like the window size and count and packet size info on a per-
channel basis. In addition if the channel is tied to a forwarded port
we also record port-forwarding information (recorded in the generic
channel-type and channel-type-argument strings) */
typedef struct {
/* General channel info. The read and write channel numbers are the
same for everything but Cisco software */
int channelID; /* cryptlib-level channel ID */
long readChannelNo, writeChannelNo; /* SSH-level channel ID */
int flags; /* Channel flags */
/* External interface information */
CRYPT_ATTRIBUTE_TYPE cursorPos; /* Virtual cursor position */
/* Channel parameters */
long windowCount; /* Current window usage */
int maxPacketSize; /* Max allowed packet size */
/* Channel naming information */
char type[ CRYPT_MAX_TEXTSIZE ], arg1[ CRYPT_MAX_TEXTSIZE ];
char arg2[ CRYPT_MAX_TEXTSIZE ];
int typeLen, arg1Len, arg2Len;
/* Channel extra data. This contains encoded oddball protocol-specific
SSH packets to be sent or having been received */
BYTE extraData[ ( UINT_SIZE + CRYPT_MAX_TEXTSIZE ) + \
( UINT_SIZE * 4 ) ];
} SSH_CHANNEL_INFO;
/* Check whether a channel corresponds to a null channel (a placeholder used
when there's currently no channel active) and whether a channel is
currently active */
#define isNullChannel( channelInfoPtr ) \
( ( channelInfoPtr )->readChannelNo == UNUSED_CHANNEL_NO )
#define isActiveChannel( channelInfoPtr ) \
( channelInfoPtr->flags & CHANNEL_FLAG_ACTIVE )
/* The maximum allowed number of channels */
#define SSH_MAX_CHANNELS 4
#ifdef USE_SSH2
/****************************************************************************
* *
* Utility Functions *
* *
****************************************************************************/
/* Check whether there are any active channels still present. Since a
channel can be half-closed (we've closed it for write but the other
side hasn't acknowledged the close yet), we allow the caller to specify
an excluded channel ID that's treated as logically closed for active
channel-check purposes even if a channel entry is still present for it.
In addition we allow a count parameter to allow checking for whether
a set of channels is still open */
static BOOLEAN isChannelActive( const SESSION_INFO *sessionInfoPtr,
const int excludedChannelID,
const int channelCount )
{
ATTRIBUTE_LIST *attributeListPtr;
int count = channelCount;
for( attributeListPtr = sessionInfoPtr->attributeList;
attributeListPtr != NULL; attributeListPtr = attributeListPtr->next )
{
const SSH_CHANNEL_INFO *channelInfoPtr;
/* If it's not an SSH channel. continue */
if( attributeListPtr->attribute != CRYPT_SESSINFO_SSH_CHANNEL )
continue;
/* It's an SSH channel, check whether it's the one that we're
after */
assert( attributeListPtr->valueLength == sizeof( SSH_CHANNEL_INFO ) );
channelInfoPtr = attributeListPtr->value;
if( isActiveChannel( channelInfoPtr ) && \
channelInfoPtr->channelID != excludedChannelID )
{
/* It's the one that we're after, if a sufficient number of
matches have been found, we're done */
count--;
if( count <= 0 )
return( TRUE );
}
}
return( FALSE );
}
/* Helper function used to access SSH-specific internal attributes within
an attribute group */
static int accessFunction( ATTRIBUTE_LIST *attributeListPtr,
const ATTR_TYPE attrGetType )
{
static const CRYPT_ATTRIBUTE_TYPE attributeOrderList[] = {
CRYPT_SESSINFO_SSH_CHANNEL, CRYPT_SESSINFO_SSH_CHANNEL_TYPE,
CRYPT_SESSINFO_SSH_CHANNEL_ARG1, CRYPT_SESSINFO_SSH_CHANNEL_ARG2,
CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE, CRYPT_ATTRIBUTE_NONE,
CRYPT_ATTRIBUTE_NONE };
SSH_CHANNEL_INFO *channelInfoPtr = attributeListPtr->value;
CRYPT_ATTRIBUTE_TYPE attributeType = channelInfoPtr->cursorPos;
BOOLEAN doContinue;
/* If we've just moved the cursor onto this attribute, reset the
position to the first internal attribute */
if( attributeListPtr->flags & ATTR_FLAG_CURSORMOVED )
{
attributeType = channelInfoPtr->cursorPos = \
CRYPT_SESSINFO_SSH_CHANNEL;
attributeListPtr->flags &= ~ATTR_FLAG_CURSORMOVED;
}
/* If it's an info fetch, return the currently-selected attribute */
if( attrGetType == ATTR_NONE )
return( attributeType );
do
{
int i;
/* Find the position of the current sub-attribute in the attribute
order list and use that to get its successor/predecessor sub-
attribute */
for( i = 0; \
attributeOrderList[ i ] != attributeType && \
attributeOrderList[ i ] != CRYPT_ATTRIBUTE_NONE; i++ );
if( attributeOrderList[ i ] == CRYPT_ATTRIBUTE_NONE )
attributeType = CRYPT_ATTRIBUTE_NONE;
else
if( attrGetType == ATTR_PREV )
attributeType = ( i < 1 ) ? CRYPT_ATTRIBUTE_NONE : \
attributeOrderList[ i - 1 ];
else
attributeType = attributeOrderList[ i + 1 ];
if( attributeType == CRYPT_ATTRIBUTE_NONE )
/* We've reached the first/last sub-attribute within the current
item/group, tell the caller that there are no more sub-
attributes present and they have to move on to the next
group */
return( FALSE );
/* Check whether the required sub-attribute is present. If not, we
continue and try the next one */
doContinue = FALSE;
switch( attributeType )
{
case CRYPT_SESSINFO_SSH_CHANNEL:
case CRYPT_SESSINFO_SSH_CHANNEL_TYPE:
case CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE:
break; /* Always present */
case CRYPT_SESSINFO_SSH_CHANNEL_ARG1:
if( channelInfoPtr->arg1Len <= 0 )
doContinue = TRUE;
break;
case CRYPT_SESSINFO_SSH_CHANNEL_ARG2:
if( channelInfoPtr->arg2Len <= 0 )
doContinue = TRUE;
break;
default:
assert( NOTREACHED );
return( FALSE );
}
}
while( doContinue );
channelInfoPtr->cursorPos = attributeType;
return( TRUE );
}
/****************************************************************************
* *
* Find Channel Information *
* *
****************************************************************************/
/* Find the attribute entry for a channel */
static ATTRIBUTE_LIST *findChannelAttr( const SESSION_INFO *sessionInfoPtr,
const long channelNo )
{
ATTRIBUTE_LIST *attributeListPtr;
for( attributeListPtr = sessionInfoPtr->attributeList;
attributeListPtr != NULL; attributeListPtr = attributeListPtr->next )
{
const SSH_CHANNEL_INFO *channelInfoPtr;
/* If it's not an SSH channel. continue */
if( attributeListPtr->attribute != CRYPT_SESSINFO_SSH_CHANNEL )
continue;
/* It's an SSH channel, check whether it's the one that we're
after */
assert( attributeListPtr->valueLength == sizeof( SSH_CHANNEL_INFO ) );
channelInfoPtr = attributeListPtr->value;
if( channelInfoPtr->readChannelNo == channelNo || \
channelInfoPtr->writeChannelNo == channelNo )
return( attributeListPtr );
}
return( NULL );
}
/* Find the channel info for a channel, matching by channel number, channel
ID, and channel host + port information */
static SSH_CHANNEL_INFO *findChannelInfo( const SESSION_INFO *sessionInfoPtr,
const long channelNo )
{
const ATTRIBUTE_LIST *attributeListPtr = \
findChannelAttr( sessionInfoPtr, channelNo );
return( ( attributeListPtr == NULL ) ? NULL : attributeListPtr->value );
}
static SSH_CHANNEL_INFO *findChannelInfoID( const SESSION_INFO *sessionInfoPtr,
const int channelID )
{
ATTRIBUTE_LIST *attributeListPtr;
assert( channelID != UNUSED_CHANNEL_ID );
for( attributeListPtr = sessionInfoPtr->attributeList;
attributeListPtr != NULL; attributeListPtr = attributeListPtr->next )
{
const SSH_CHANNEL_INFO *channelInfoPtr;
/* If it's not an SSH channel. continue */
if( attributeListPtr->attribute != CRYPT_SESSINFO_SSH_CHANNEL )
continue;
/* It's an SSH channel, check whether it's the that one we're
after */
assert( attributeListPtr->valueLength == sizeof( SSH_CHANNEL_INFO ) );
channelInfoPtr = attributeListPtr->value;
if( channelInfoPtr->channelID == channelID )
return( ( SSH_CHANNEL_INFO * ) channelInfoPtr );
}
return( NULL );
}
static SSH_CHANNEL_INFO *findChannelInfoAddr( const SESSION_INFO *sessionInfoPtr,
const char *addrInfo,
const int addrInfoLen )
{
ATTRIBUTE_LIST *attributeListPtr;
assert( isReadPtr( addrInfo, addrInfoLen ) );
for( attributeListPtr = sessionInfoPtr->attributeList;
attributeListPtr != NULL; attributeListPtr = attributeListPtr->next )
{
const SSH_CHANNEL_INFO *channelInfoPtr;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -