⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ssh2_chn.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 3 页
字号:
				const int maxPacketSize, const void *type,
				const int typeLen, const void *arg1, const int arg1Len )
	{
	ATTRIBUTE_LIST *attributeListPtr;
	SSH_INFO *sshInfo = sessionInfoPtr->sessionSSH;
	SSH_CHANNEL_INFO channelInfo;
	int channelCount = 0, iterationCount = 0, status;

	assert( channelNo >= 0 );
	assert( maxPacketSize >= 1024 && maxPacketSize <= 0x100000L );
	assert( isReadPtr( type, typeLen ) );
	assert( ( arg1 == NULL && arg1Len == 0 ) || 
			isReadPtr( arg1, arg1Len ) );

	/* Make sure that this channel doesn't already exist */
	if( findChannelInfo( sessionInfoPtr, channelNo ) != NULL )
		{
		retExt( CRYPT_ERROR_DUPLICATE,
				( CRYPT_ERROR_DUPLICATE, SESSION_ERRINFO, 
				  "Attempt to add duplicate channel %ld", channelNo ) );
		}

	/* SSH channels are allocated unique IDs for tracking by cryptlib,
	   since (at least in theory) the SSH-level channel IDs may repeat.
	   If the initial (not-yet-initialised) channel ID matches the
	   UNUSED_CHANNEL_ID magic value, we initialise it to one past that
	   value */
	if( sshInfo->channelIndex <= UNUSED_CHANNEL_ID )
		sshInfo->channelIndex = UNUSED_CHANNEL_ID + 1;

	/* Make sure that we haven't exceeded the maximum number of channels */
	for( attributeListPtr = sessionInfoPtr->attributeList;
		 attributeListPtr != NULL && \
			iterationCount++ < FAILSAFE_ITERATIONS_MAX;
		 attributeListPtr = attributeListPtr->next )
		{
		if( attributeListPtr->attributeID == CRYPT_SESSINFO_SSH_CHANNEL )
			channelCount++;
		}
	if( iterationCount >= FAILSAFE_ITERATIONS_MAX )
		retIntError();
	if( channelCount > SSH_MAX_CHANNELS )
		{
		retExt( CRYPT_ERROR_OVERFLOW,
				( CRYPT_ERROR_OVERFLOW, SESSION_ERRINFO, 
				  "Maximum number (%d) of SSH channels reached",
				  SSH_MAX_CHANNELS ) );
		}

	/* Initialise the info for the new channel and create it */
	memset( &channelInfo, 0, sizeof( SSH_CHANNEL_INFO ) );
	channelInfo.channelID = sshInfo->channelIndex++;
	channelInfo.readChannelNo = channelInfo.writeChannelNo = channelNo;
	channelInfo.maxPacketSize = maxPacketSize;
	status = attributeCopyParams( channelInfo.type, CRYPT_MAX_TEXTSIZE, 
								  &channelInfo.typeLen, type, typeLen );
	if( cryptStatusOK( status ) && arg1 != NULL )
		status = attributeCopyParams( channelInfo.arg1, CRYPT_MAX_TEXTSIZE, 
									  &channelInfo.arg1Len, arg1, arg1Len );
	if( cryptStatusOK( status ) )
		status = addSessionInfoComposite( &sessionInfoPtr->attributeList,
							CRYPT_SESSINFO_SSH_CHANNEL, accessFunction,
							&channelInfo, sizeof( SSH_CHANNEL_INFO ),
							ATTR_FLAG_MULTIVALUED | ATTR_FLAG_COMPOSITE );
	if( cryptStatusError( status ) )
		return( status );

	/* Select the newly-created channel.  We have to select it using the
	   special-case indicator of CHANNEL_NONE since we can't normally
	   select an inactive channel */
	return( selectChannel( sessionInfoPtr, channelNo, CHANNEL_NONE ) );
	}

int createChannel( SESSION_INFO *sessionInfoPtr )
	{
	SSH_INFO *sshInfo = sessionInfoPtr->sessionSSH;
	int iterationCount = 0;

	/* Find an unused channel number.  Since the peer can request the
	   creation of arbitrary-numbered channels, we have to be careful to
	   ensure that we don't clash with any existing peer-requested channel
	   numbers when we create our own channel */
	while( findChannelInfo( sessionInfoPtr, \
							sshInfo->nextChannelNo ) != NULL && \
		   iterationCount++ < FAILSAFE_ITERATIONS_MED )
		sshInfo->nextChannelNo++;
	if( iterationCount >= FAILSAFE_ITERATIONS_MED )
		retIntError();

	/* Create a channel with the new channel number */
	return( addChannel( sessionInfoPtr, sshInfo->nextChannelNo++,
						sessionInfoPtr->sendBufSize - EXTRA_PACKET_SIZE,
						"session", 7, NULL, 0 ) );
	}

int deleteChannel( SESSION_INFO *sessionInfoPtr, const long channelNo,
				   const CHANNEL_TYPE channelType,
				   const BOOLEAN deleteLastChannel )
	{
	SSH_INFO *sshInfo = sessionInfoPtr->sessionSSH;
	SSH_CHANNEL_INFO *channelInfoPtr;
	ATTRIBUTE_LIST *attributeListPtr;
	int channelID;

	/* If we can't delete the last remaining channel (it has to be done
	   explicitly via a session close) and there are less than two active
	   channels left, we can't do anything */
	if( !deleteLastChannel && \
		!isChannelActive( sessionInfoPtr, UNUSED_CHANNEL_ID, 2 ) )
		return( CRYPT_ERROR_PERMISSION );

	/* Locate the channel info */
	attributeListPtr = findChannelAttr( sessionInfoPtr, channelNo );
	if( attributeListPtr == NULL )
		return( isChannelActive( sessionInfoPtr, UNUSED_CHANNEL_ID, 1 ) ? \
				CRYPT_ERROR_NOTFOUND : OK_SPECIAL );
	channelInfoPtr = attributeListPtr->value;
	channelID = channelInfoPtr->channelID;

	/* Delete the channel entry.  If we're only closing the write side we
	   mark the channel as closed for write but leave the overall channel
	   open */
	if( channelType == CHANNEL_WRITE )
		{
		assert( !( channelInfoPtr->flags & CHANNEL_FLAG_WRITECLOSED ) );
		channelInfoPtr->flags |= CHANNEL_FLAG_WRITECLOSED;
		if( channelID == sshInfo->currWriteChannel )
			sshInfo->currWriteChannel = UNUSED_CHANNEL_ID;
		return( isChannelActive( sessionInfoPtr, \
								 channelInfoPtr->channelID, 1 ) ? \
				CRYPT_OK : OK_SPECIAL );
		}
	deleteSessionInfo( &sessionInfoPtr->attributeList,
					   &sessionInfoPtr->attributeListCurrent,
					   attributeListPtr );

	/* If we've deleted the current channel, select a null channel until a
	   new one is created/selected */
	if( channelID == sshInfo->currReadChannel )
		sshInfo->currReadChannel = UNUSED_CHANNEL_ID;
	if( channelID == sshInfo->currWriteChannel )
		sshInfo->currWriteChannel = UNUSED_CHANNEL_ID;

	/* We've deleted an open channel, check if there are any channels left
	   and if not let the caller know */
	return( isChannelActive( sessionInfoPtr, UNUSED_CHANNEL_ID, 1 ) ? \
			CRYPT_OK : OK_SPECIAL );
	}

#if 0

int deleteChannelAddr( SESSION_INFO *sessionInfoPtr, const char *addrInfo,
					   const int addrInfoLen )
	{
	const SSH_CHANNEL_INFO *channelInfoPtr;

	channelInfoPtr = findChannelInfoAddr( sessionInfoPtr, addrInfo,
										  addrInfoLen );
	if( channelInfoPtr == NULL )
		return( CRYPT_ERROR_NOTFOUND );

	/* We've found the entry that it corresponds to, clear it.  This doesn't
	   actually delete the entire channel, but merely deletes the forwarding.
	   See the note in ssh2_msg.c for why this is currently unused */
	memset( channelInfoPtr->arg1, 0, CRYPT_MAX_TEXTSIZE );
	channelInfoPtr->arg1Len = 0;
	return( CRYPT_OK );
	}
#endif /* 0 */

/****************************************************************************
*																			*
*							Enqueue/Send Channel Messages					*
*																			*
****************************************************************************/

/* Enqueue a response to a request, to be sent at the next available
   opportunity.  This is required because we may be in the middle of
   assembling or sending a data packet when we need to send the response,
   so the response has to be deferred until after the data packet has been
   completed and sent */

int enqueueResponse( SESSION_INFO *sessionInfoPtr, const int type,
					 const int noParams, const long channelNo,
					 const int param1, const int param2, const int param3 )
	{
	SSH_RESPONSE_INFO *respPtr = &sessionInfoPtr->sessionSSH->response;
	STREAM stream;
	int status = CRYPT_OK;

	/* If there's already a response enqueued, we can't enqueue another one
	   until it's been sent */
	if( respPtr->type != 0 )
		retIntError();

	respPtr->type = type;
	sMemOpen( &stream, respPtr->data, SSH_MAX_RESPONSESIZE );
	if( noParams > 0 )
		status = writeUint32( &stream, channelNo );
	if( noParams > 1 )
		status = writeUint32( &stream, param1 );
	if( noParams > 2 )
		status = writeUint32( &stream, param2 );
	if( noParams > 3 )
		status = writeUint32( &stream, param3 );
	ENSURES( cryptStatusOK( status ) );
	respPtr->dataLen = stell( &stream );
	sMemDisconnect( &stream );

	return( CRYPT_OK );
	}

/* Assemble a packet for and send a previously enqueued response */

int sendEnqueuedResponse( SESSION_INFO *sessionInfoPtr, const int offset )
	{
	SSH_RESPONSE_INFO *respPtr = &sessionInfoPtr->sessionSSH->response;
	STREAM stream;
	int sendBufOffset = ( offset == CRYPT_UNUSED ) ? \
						sessionInfoPtr->sendBufPos : offset;
	int status;

	assert( sendBufOffset >= 0 );

	/* If there's an incomplete packet in the process of being assembled in
	   the send buffer, we can't do anything */
	if( !sessionInfoPtr->partialWrite && \
		( sendBufOffset > sessionInfoPtr->sendBufStartOfs ) )
		return( CRYPT_OK );

	/* Either the send buffer's empty or it contains a completed packet in
	   the process of being written, if there's not enough room for the
	   enqueued response we can't do anything */
	if( sendBufOffset + ( 32 + CRYPT_MAX_HASHSIZE + CRYPT_MAX_IVSIZE ) > \
		sessionInfoPtr->sendBufSize )
		return( CRYPT_OK );

	assert( ( sendBufOffset <= sessionInfoPtr->sendBufStartOfs ) || \
			( sessionInfoPtr->partialWrite && \
			  sendBufOffset + ( 32 + CRYPT_MAX_HASHSIZE + CRYPT_MAX_IVSIZE ) < \
			  sessionInfoPtr->sendBufSize ) );

	/* If there's nothing in the send buffer, set the start offset to zero.
	   We have to do this because it's pre-adjusted to accomodate the header
	   for a payload data packet, since we're assembling our own packet in
	   the buffer there's no need for this additional header room */
	if( sendBufOffset == sessionInfoPtr->sendBufStartOfs )
		sessionInfoPtr->sendBufPos = sendBufOffset = 0;

	/* Assemble the response as a new packet at the end of any existing
	   data */
	sMemOpen( &stream, sessionInfoPtr->sendBuffer + sendBufOffset,
			  sessionInfoPtr->sendBufSize - sendBufOffset );
	swrite( &stream, "\x00\x00\x00\x00\x00", SSH2_HEADER_SIZE );
	status = sputc( &stream, respPtr->type );
	if( respPtr->dataLen > 0 )
		{
		/* Some responses can consist purely of an ID byte */
		status = swrite( &stream, respPtr->data, respPtr->dataLen );
		}
	if( cryptStatusOK( status ) )
		status = wrapPacketSSH2( sessionInfoPtr, &stream, 0, FALSE, TRUE );
	if( cryptStatusError( status ) )
		{
		sMemDisconnect( &stream );
		return( status );
		}

	/* If we're only assembling the data and the caller is taking care of
	   sending the assembled packet, we're done */
	if( offset != CRYPT_UNUSED )
		return( CRYPT_OK );

	/* We've sent (or at least assembled) the response, clear the enqueued
	   data */
	memset( respPtr, 0, sizeof( SSH_RESPONSE_INFO ) );

	/* Try and write the response */
	if( sessionInfoPtr->flags & SESSION_ISOPEN )
		{
		int dummy;

		/* We're in the data transfer phase, use the standard data-flush
		   mechanism to try and get the data out.  We set the partial-write
		   flag because what we've just added is pre-packaged data that
		   doesn't have to go through the data-payload encoding process */
		sessionInfoPtr->sendBufPos += stell( &stream );
		sessionInfoPtr->partialWrite = TRUE;
		status = putSessionData( sessionInfoPtr, NULL, 0, &dummy );
		}
	else
		{
		/* We're still in the handshake phase, we can send the packet
		   directly */
		status = sendPacketSSH2( sessionInfoPtr, &stream, TRUE );
		}
	sMemDisconnect( &stream );

	return( status );
	}

/* Enqueue channel control data ready to be sent, and try and send it if
   possible */

int enqueueChannelData( SESSION_INFO *sessionInfoPtr, const int type,
						const long channelNo, const int param )
	{
	int status;

	status = enqueueResponse( sessionInfoPtr, type, 2, channelNo, param,
							  CRYPT_UNUSED, CRYPT_UNUSED );
	return( cryptStatusOK( status ) ? \
			sendEnqueuedResponse( sessionInfoPtr, CRYPT_UNUSED ) : status );
	}

/* Append enqueued channel control data to existing channel payload data
   without trying to send it (the data send is being piggybacked on a
   payload data send and will be handled by the caller) */

int appendChannelData( SESSION_INFO *sessionInfoPtr, const int offset )
	{
	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
	assert( offset >= 0 && offset < sessionInfoPtr->sendBufSize );

	return( sendEnqueuedResponse( sessionInfoPtr, offset ) );
	}
#endif /* USE_SSH */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -