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

📄 ssh2_msg.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 5 页
字号:
		status = wrapPacketSSH2( sessionInfoPtr, stream, 0, FALSE, TRUE );
	return( status );
	}

static int createSessionOpenRequest( SESSION_INFO *sessionInfoPtr,
									 STREAM *stream )
	{
	const long channelNo = getCurrentChannelNo( sessionInfoPtr,
												CHANNEL_WRITE );
	BYTE typeString[ CRYPT_MAX_TEXTSIZE + 8 ];
	int typeLen, packetOffset, status;

	/* If the caller has requested the use of a custom subsystem (and at the
	   moment the only one that's likely to be used is SFTP), request this
	   from the server by modifying the channel that we've just opened to
	   run the subsystem */
	status = getChannelAttributeString( sessionInfoPtr, 
										CRYPT_SESSINFO_SSH_CHANNEL_TYPE,
										typeString, CRYPT_MAX_TEXTSIZE, 
										&typeLen );
	if( cryptStatusError( status ) )
		return( status );
	if( !strCompare( typeString, "subsystem", 9 ) )
		{
		BYTE arg1String[ CRYPT_MAX_TEXTSIZE + 8 ];
		int arg1Len;

		/* Get the subsystem type */
		status = getChannelAttributeString( sessionInfoPtr, 
											CRYPT_SESSINFO_SSH_CHANNEL_ARG1,
											arg1String, CRYPT_MAX_TEXTSIZE, 
											&arg1Len );
		if( cryptStatusError( status ) )
			return( status );

		/*	byte	type = SSH2_MSG_CHANNEL_REQUEST
			uint32	recipient_channel
			string	request_name = "subsystem"
			boolean	want_reply = FALSE
			string	subsystem_name */
		status = openPacketStreamSSH( stream, sessionInfoPtr, 
									  CRYPT_USE_DEFAULT,
									  SSH2_MSG_CHANNEL_REQUEST );
		if( cryptStatusError( status ) )
			return( status );
		writeUint32( stream, channelNo );
		writeString32( stream, "subsystem", 9 );
		sputc( stream, 0 );
		status = writeString32( stream, arg1String, arg1Len );
		if( cryptStatusOK( status ) )
			status = wrapPacketSSH2( sessionInfoPtr, stream, 0, FALSE, TRUE );
		return( status );
		}

	/* If the caller has requested the use of remote command execution (i.e. 
	   an rexec rather than the usual SSH rsh), run the command directly
	   without going via a pty */
	if( !strCompare( typeString, "exec", 4 ) )
		{
		BYTE arg1String[ CRYPT_MAX_TEXTSIZE + 8 ];
		int arg1Len;

		/* Get the command to execute */
		status = getChannelAttributeString( sessionInfoPtr, 
											CRYPT_SESSINFO_SSH_CHANNEL_ARG1,
											arg1String, CRYPT_MAX_TEXTSIZE, 
											&arg1Len );
		if( cryptStatusError( status ) )
			return( status );

		/*	byte	type = SSH2_MSG_CHANNEL_REQUEST
			uint32	recipient_channel
			string	request_name = "exec"
			boolean	want_reply = FALSE
			string	command */
		status = openPacketStreamSSH( stream, sessionInfoPtr, 
									  CRYPT_USE_DEFAULT,
									  SSH2_MSG_CHANNEL_REQUEST );
		if( cryptStatusError( status ) )
			return( status );
		writeUint32( stream, channelNo );
		writeString32( stream, "exec", 4 );
		sputc( stream, 0 );
		status = writeString32( stream, arg1String, arg1Len );
		if( cryptStatusOK( status ) )
			status = wrapPacketSSH2( sessionInfoPtr, stream, 0, FALSE, TRUE );
		return( status );
		}

	/* It's a standard channel open:

		byte	type = SSH2_MSG_CHANNEL_REQUEST
		uint32	recipient_channel
		string	request_name = "pty-req"
		boolean	want_reply = FALSE
		string	TERM_environment_variable = "xterm"
		uint32	cols = 80
		uint32	rows = 48
		uint32	pixel_width = 0
		uint32	pixel_height = 0
		string	tty_mode_info = ""
		... */
	status = openPacketStreamSSH( stream, sessionInfoPtr, CRYPT_USE_DEFAULT,
								  SSH2_MSG_CHANNEL_REQUEST );
	if( cryptStatusError( status ) )
		return( status );
	writeUint32( stream, channelNo );
	writeString32( stream, "pty-req", 7 );
	sputc( stream, 0 );					/* No reply */
	writeString32( stream, "xterm", 5 );/* Generic */
	writeUint32( stream, 80 );
	writeUint32( stream, 48 );			/* 48 x 80 (we're past 24 x 80) */
	writeUint32( stream, 0 );
	writeUint32( stream, 0 );			/* No graphics capabilities */
	status = writeUint32( stream, 0 );	/* No special TTY modes */
	if( cryptStatusOK( status ) )
		status = wrapPacketSSH2( sessionInfoPtr, stream, 0, FALSE, TRUE );
	if( cryptStatusError( status ) )
		return( status );

	/*	...
		byte	type = SSH2_MSG_CHANNEL_REQUEST
		uint32	recipient_channel
		string	request_name = "shell"
		boolean	want_reply = FALSE

	   This final request, once sent, moves the server into interactive
	   session mode */
	status = continuePacketStreamSSH( stream, SSH2_MSG_CHANNEL_REQUEST,
									  &packetOffset );
	if( cryptStatusError( status ) )
		return( status );
	writeUint32( stream, channelNo );
	writeString32( stream, "shell", 5 );
	status = sputc( stream, 0 );			/* No reply */
	if( cryptStatusOK( status ) )
		status = wrapPacketSSH2( sessionInfoPtr, stream, packetOffset, 
								 FALSE, TRUE );
	return( status );
	}

/* Send a channel open */

int sendChannelOpen( SESSION_INFO *sessionInfoPtr )
	{
	STREAM stream;
	OPENREQUEST_TYPE requestType;
	const long channelNo = getCurrentChannelNo( sessionInfoPtr,
												CHANNEL_READ );
	long currentChannelNo;
	int length, value, status;

	/* Make sure that there's channel data available to activate and
	   that it doesn't correspond to an already-active channel */
	if( channelNo == UNUSED_CHANNEL_NO )
		{
		retExt( CRYPT_ERROR_NOTINITED,
				( CRYPT_ERROR_NOTINITED, SESSION_ERRINFO, 
				  "No current channel information available to activate "
				  "channel" ) );
		}
	status = getChannelAttribute( sessionInfoPtr,
								  CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE,
								  &value );
	if( cryptStatusError( status ) || value )
		{
		retExt( CRYPT_ERROR_INITED,
				( CRYPT_ERROR_INITED, SESSION_ERRINFO, 
				  "Current channel has already been activated" ) );
		}

	/* Create a request for the appropriate type of service */
	status = createOpenRequest( sessionInfoPtr, &stream, &requestType );
	if( cryptStatusError( status ) )
		{
		sMemDisconnect( &stream );
		return( status );
		}

	/* If it's a request-only message that doesn't open a channel,send it
	   and exit */
	if( requestType == OPENREQUEST_STANDALONE )
		{
		status = sendPacketSSH2( sessionInfoPtr, &stream, TRUE );
		sMemDisconnect( &stream );
		return( status );
		}

	/* Send the open request to the server.  The SSHv2 spec doesn't really
	   explain the semantics of the server's response to the channel open
	   command, in particular whether the returned data size parameters are
	   merely a confirmation of the client's requested values or whether the
	   server is allowed to further modify them to suit its own requirements
	   (or perhaps one is for send and the other for receive?).  In the
	   absence of any further guidance, we just ignore the returned values,
	   which seems to work for all deployed servers */
	status = sendPacketSSH2( sessionInfoPtr, &stream, TRUE );
	sMemDisconnect( &stream );
	if( cryptStatusError( status ) )
		return( status );

	/* Wait for the server's ack of the channel open request:

		byte	SSH_MSG_CHANNEL_OPEN_CONFIRMATION
		uint32	recipient_channel
		uint32	sender_channel
		uint32	initial_window_size
		uint32	maximum_packet_size
		... */
	status = length = \
		readHSPacketSSH2( sessionInfoPtr, SSH2_MSG_SPECIAL_CHANNEL,
						  ID_SIZE + UINT32_SIZE + UINT32_SIZE + \
							UINT32_SIZE + UINT32_SIZE );
	if( cryptStatusError( status ) )
		return( status );
	sMemConnect( &stream, sessionInfoPtr->receiveBuffer, length );
	if( sgetc( &stream ) == SSH2_MSG_CHANNEL_OPEN_FAILURE )
		{
		ERROR_INFO *errorInfo = &sessionInfoPtr->errorInfo;
		BYTE stringBuffer[ CRYPT_MAX_TEXTSIZE + 8 ];
		int stringLen;

		/* The channel open failed, tell the caller why:

			byte	SSH_MSG_CHANNEL_OPEN_FAILURE
			uint32	recipient_channel
			uint32	reason_code
			string	additional_text */
		readUint32( &stream );		/* Skip channel number */
		errorInfo->errorCode = readUint32( &stream );
		status = readString32( &stream, stringBuffer, CRYPT_MAX_TEXTSIZE, 
							   &stringLen );
		if( cryptStatusError( status ) || \
			stringLen <= 0 || stringLen > CRYPT_MAX_TEXTSIZE )
			{
			/* No error message, the best that we can do is give the reason
			   code as part of the message */
			retExt( CRYPT_ERROR_OPEN,
					( CRYPT_ERROR_OPEN, SESSION_ERRINFO, 
					  "Channel open failed, reason code %d",
					  errorInfo->errorCode ) );
			}
		retExt( CRYPT_ERROR_OPEN,
				( CRYPT_ERROR_OPEN, SESSION_ERRINFO, 
				  "Channel open failed, error message '%s'",
				  sanitiseString( stringBuffer, CRYPT_MAX_TEXTSIZE, 
								  stringLen ) ) );
		}
	currentChannelNo = readUint32( &stream );
	if( currentChannelNo != channelNo )
		{
		sMemDisconnect( &stream );
		retExt( CRYPT_ERROR_BADDATA,
				( CRYPT_ERROR_BADDATA, SESSION_ERRINFO, 
				  "Invalid channel number %ld in channel open confirmation, "
				  "should be %ld", currentChannelNo, channelNo ) );
		}
	currentChannelNo = readUint32( &stream );
	sMemDisconnect( &stream );

	/* The channel has been successfully created, mark it as active and
	   select it for future exchanges */
	status = setChannelExtAttribute( sessionInfoPtr, SSH_ATTRIBUTE_ACTIVE,
									 NULL, TRUE );
	if( cryptStatusOK( status ) && currentChannelNo != channelNo )
		{
		/* It's unclear why anyone would want to use different channel
		   numbers for different directions since it's the same channel that 
		   the data is moving across, but Cisco do it anyway */
		status = setChannelExtAttribute( sessionInfoPtr, 
										 SSH_ATTRIBUTE_ALTCHANNELNO,
										 NULL, currentChannelNo );
		}
	if( cryptStatusOK( status ) )
		status = selectChannel( sessionInfoPtr, channelNo, CHANNEL_BOTH );
	if( cryptStatusError( status ) )
		return( status );
	if( requestType == OPENREQUEST_CHANNELONLY )
		{
		/* If we're just opening a new channel in an existing session, we're 
		   done */
		return( CRYPT_OK );
		}
	assert( requestType == OPENREQUEST_SESSION );

	/* It's a session open request that requires additional messages to do
	   anything useful, create and send the extra packets */
	status = createSessionOpenRequest( sessionInfoPtr, &stream );
	if( cryptStatusOK( status ) )
		status = sendPacketSSH2( sessionInfoPtr, &stream, TRUE );
	sMemDisconnect( &stream );
	return( status );
	}

/****************************************************************************
*																			*
*							Server-side Channel Management					*
*																			*
****************************************************************************/

/* SSH identifies channel requests using awkward string-based identifiers,
   to make these easier to work with we map them to integer values */

typedef enum { REQUEST_NONE, REQUEST_SUBSYSTEM, REQUEST_SHELL, REQUEST_EXEC,
			   REQUEST_PORTFORWARD, REQUEST_PORTFORWARD_CANCEL, REQUEST_PTY,
			   REQUEST_NOOP, REQUEST_DISALLOWED } REQUEST_TYPE;

#define REQUEST_FLAG_NONE		0x00/* No request flag */
#define REQUEST_FLAG_TERMINAL	0x01/* Request ends negotiation */

typedef struct {
	const char FAR_BSS *requestName;/* String form of request type */
	const REQUEST_TYPE requestType;	/* Integer form of request type */
	const int flags;				/* Request flags */
	} REQUEST_TYPE_INFO;

/* Process a global or channel request */

static int sendRequestResponse( SESSION_INFO *sessionInfoPtr,
								const long channelNo,
								const BOOLEAN isChannelRequest,
								const BOOLEAN isSuccessful )
	{
	int status;

	/* Indicate that the request succeeded/was denied:

		byte	type = SSH2_MSG_CHANNEL/GLOBAL_SUCCESS/FAILURE

⌨️ 快捷键说明

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