27 #ifdef USE_SSH_EXTENDED
28 typedef enum { REQUEST_NONE, REQUEST_SUBSYSTEM, REQUEST_SHELL, REQUEST_EXEC,
29 REQUEST_PORTFORWARD, REQUEST_PORTFORWARD_CANCEL, REQUEST_PTY,
30 REQUEST_NOOP, REQUEST_DISALLOWED } REQUEST_TYPE;
32 typedef enum { REQUEST_NONE, REQUEST_SHELL, REQUEST_PTY, REQUEST_NOOP,
33 REQUEST_DISALLOWED } REQUEST_TYPE;
36 #define REQUEST_FLAG_NONE 0x00
37 #define REQUEST_FLAG_TERMINAL 0x01
41 const
char FAR_BSS *requestName;
42 const int requestNameLength;
43 const REQUEST_TYPE requestType;
49 const
char FAR_BSS *channelName;
50 const int channelNameLength;
60 #ifdef USE_SSH_EXTENDED
74 char portBuffer[ 16 + 8 ];
79 assert(
isWritePtr( hostInfo, hostInfoMaxLen ) );
80 assert(
isWritePtr( hostInfoLen,
sizeof(
int ) ) );
86 memset( hostInfo, 0, hostInfoMaxLen );
100 "Invalid host name value" ) );
102 if( stringLength > hostInfoMaxLen )
105 stringLength = hostInfoMaxLen;
107 status = port = readUint32( stream );
112 "Invalid port number value" ) );
119 portLength =
sprintf_s( portBuffer, 8,
":%d", port );
120 memcpy( hostInfo, stringBuffer, stringLength );
121 if( stringLength + portLength <= hostInfoMaxLen )
123 memcpy( hostInfo + stringLength, portBuffer, portLength );
124 stringLength += portLength;
145 assert(
isWritePtr( hostInfo, hostInfoMaxLen ) );
146 assert(
isWritePtr( hostInfoLen,
sizeof(
int ) ) );
152 status = readAddressAndPort( sessionInfoPtr, stream, hostInfo,
153 hostInfoMaxLen, hostInfoLen );
156 if( getChannelStatusByAddr( sessionInfoPtr, hostInfo, \
163 "Received duplicate request for existing host/port %s",
164 sanitiseString( hostInfo, *hostInfoLen, *hostInfoLen ) ) );
187 status = readAddressAndPort( sessionInfoPtr, stream, hostInfo,
188 hostInfoMaxLen, &hostInfoLen );
191 return( deleteChannelAddr( sessionInfoPtr, addrInfo,
addrInfoLen ) );
210 ( channelNo >= 0 && channelNo <= LONG_MAX ) );
216 status = enqueueResponse( sessionInfoPtr,
225 return( sendEnqueuedResponse( sessionInfoPtr ) );
239 status = enqueueResponse( sessionInfoPtr,
246 return( sendEnqueuedResponse( sessionInfoPtr ) );
260 static const CHANNEL_TYPE_INFO
FAR_BSS channelInfo[] = {
261 {
"session", 7,
FALSE },
262 #ifdef USE_SSH_EXTENDED
263 {
"direct-tcpip", 12,
TRUE },
270 IN const long channelNo )
276 REQUIRES( channelNo >= 0 && channelNo <= LONG_MAX );
288 status = enqueueResponse( sessionInfoPtr,
294 status = sendEnqueuedResponse( sessionInfoPtr );
302 const CHANNEL_TYPE_INFO *channelInfoPtr = NULL;
304 #ifdef USE_SSH_EXTENDED
307 BYTE *arg1Ptr = NULL;
337 "Invalid channel type in channel open message" ) );
341 for( i = 0; channelInfo[ i ].channelName != NULL && \
345 if( typeLen == channelInfo[ i ].channelNameLength && \
346 !memcmp( typeString, channelInfo[ i ].channelName,
349 channelInfoPtr = &channelInfo[ i ];
354 if( channelInfoPtr == NULL )
359 "Invalid channel-open channel type '%s'",
360 sanitiseString( typeString, CRYPT_MAX_TEXTSIZE,
363 channelNo = readUint32( stream );
364 readUint32( stream );
365 status = maxPacketSize = readUint32( stream );
370 "Invalid '%s' channel parameters",
371 channelInfoPtr->channelName ) );
373 if( maxPacketSize < 1024 || maxPacketSize > 0x100000L )
378 ( void ) sendOpenResponseFailed( sessionInfoPtr, channelNo );
381 "Invalid '%s' channel maximum packet size parameter "
382 "value %d, should be 1K...1MB",
383 channelInfoPtr->channelName, maxPacketSize ) );
385 #ifdef USE_SSH_EXTENDED
386 if( channelInfoPtr->isPortForwarding )
389 status = getAddressAndPort( sessionInfoPtr, stream,
390 arg1String, CRYPT_MAX_TEXTSIZE,
394 ( void ) sendOpenResponseFailed( sessionInfoPtr, channelNo );
397 arg1Ptr = arg1String;
400 maxPacketSize =
min( maxPacketSize, \
407 ( void ) sendOpenResponseFailed( sessionInfoPtr, channelNo );
410 "Server attempted to a open a '%s' channel to the client",
411 channelInfoPtr->channelName ) );
417 status = addChannel( sessionInfoPtr, channelNo, maxPacketSize,
418 typeString, typeLen, arg1Ptr, arg1Len );
421 ( void ) sendOpenResponseFailed( sessionInfoPtr, channelNo );
424 "Couldn't add new '%s' channel %lX",
425 channelInfoPtr->channelName, channelNo ) );
448 status = enqueueResponse( sessionInfoPtr,
450 channelNo, channelNo,
451 getWindowSize( sessionInfoPtr ),
454 status = sendEnqueuedResponse( sessionInfoPtr );
459 ( void ) deleteChannel( sessionInfoPtr, channelNo,
CHANNEL_BOTH,
470 const int windowSize = getWindowSize( sessionInfoPtr );
473 status = setChannelExtAttribute( sessionInfoPtr,
477 status = setChannelExtAttribute( sessionInfoPtr,
482 status = selectChannel( sessionInfoPtr, channelNo,
CHANNEL_BOTH );
494 static const REQUEST_TYPE_INFO
FAR_BSS requestInfo[] = {
496 {
"pty-req", 7, REQUEST_PTY, REQUEST_FLAG_NONE },
497 {
"shell", 5, REQUEST_SHELL, REQUEST_FLAG_TERMINAL },
498 #ifdef USE_SSH_EXTENDED
499 {
"subsystem", 9, REQUEST_SUBSYSTEM, REQUEST_FLAG_TERMINAL },
500 {
"tcpip-forward", 13, REQUEST_PORTFORWARD, REQUEST_FLAG_NONE },
501 {
"cancel-tcpip-forward", 20, REQUEST_PORTFORWARD_CANCEL, REQUEST_FLAG_NONE },
502 {
"exec", 4, REQUEST_EXEC, REQUEST_FLAG_TERMINAL },
506 {
"env", 3, REQUEST_NOOP, REQUEST_FLAG_NONE },
507 {
"exit-signal", 11, REQUEST_NOOP, REQUEST_FLAG_NONE },
508 {
"exit-status", 11, REQUEST_NOOP, REQUEST_FLAG_NONE },
509 {
"signal", 6, REQUEST_NOOP, REQUEST_FLAG_NONE },
510 {
"xon-xoff", 8, REQUEST_NOOP, REQUEST_FLAG_NONE },
511 {
"window-change", 13, REQUEST_NOOP, REQUEST_FLAG_NONE },
514 {
"x11-req", 7, REQUEST_DISALLOWED, REQUEST_FLAG_NONE },
515 { NULL, 0, REQUEST_NONE, REQUEST_FLAG_NONE },
516 { NULL, 0, REQUEST_NONE, REQUEST_FLAG_NONE }
525 const REQUEST_TYPE_INFO *requestInfoPtr = NULL;
526 const BOOLEAN isChannelRequest = \
528 BYTE stringBuffer[ CRYPT_MAX_TEXTSIZE + 8 ];
535 REQUIRES( prevChannelNo >= 0 && prevChannelNo <= LONG_MAX );
553 readString32( stream, stringBuffer, CRYPT_MAX_TEXTSIZE, &stringLength );
554 status = wantReply = sgetc( stream );
556 stringLength <= 0 || stringLength > CRYPT_MAX_TEXTSIZE )
560 "Invalid request type in %s request packet",
561 isChannelRequest ?
"channel" :
"global" ) );
565 for( i = 0; requestInfo[ i ].requestName != NULL && \
569 if( stringLength == requestInfo[ i ].requestNameLength && \
570 !memcmp( stringBuffer, requestInfo[ i ].requestName,
573 requestInfoPtr = &requestInfo[ i ];
583 if( requestInfoPtr == NULL || \
584 requestInfoPtr->requestType == REQUEST_DISALLOWED || \
586 requestInfoPtr->requestType != REQUEST_NOOP ) )
594 if( isChannelRequest )
599 status = sendChannelResponse( sessionInfoPtr, prevChannelNo,
601 localStatus = selectChannel( sessionInfoPtr, prevChannelNo,
604 status = localStatus;
607 status = sendGlobalResponse( sessionInfoPtr,
FALSE );
611 ENSURES( requestInfoPtr != NULL && \
613 ( requestInfoPtr->requestType == REQUEST_NOOP ) ) );
618 switch( requestInfoPtr->requestType )
627 #ifdef USE_SSH_EXTENDED
632 case REQUEST_SUBSYSTEM:
637 status = readString32( stream, stringBuffer, CRYPT_MAX_TEXTSIZE,
640 stringLength <= 0 || stringLength > CRYPT_MAX_TEXTSIZE )
650 status = setChannelAttributeS( sessionInfoPtr,
655 status = setChannelAttributeS( sessionInfoPtr,
664 case REQUEST_PORTFORWARD:
671 status = getAddressAndPort( sessionInfoPtr, stream, stringBuffer,
672 CRYPT_MAX_TEXTSIZE, &stringLength );
682 setChannelAttribute( sessionInfoPtr,
684 stringBuffer, stringLength );
689 case REQUEST_PORTFORWARD_CANCEL:
691 const int offset = stell( stream );
703 for( requestOK =
FALSE, iterationCount = 0;
707 sseek( stream, offset );
708 status = clearAddressAndPort( sessionInfoPtr, stream );
713 ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
718 case REQUEST_DISALLOWED:
728 if( isChannelRequest )
730 status = sendChannelResponse( sessionInfoPtr, prevChannelNo,
735 status = selectChannel( sessionInfoPtr, prevChannelNo,
740 status = sendGlobalResponse( sessionInfoPtr, requestOK );
746 return( ( requestInfoPtr->flags & REQUEST_FLAG_TERMINAL ) ? \