diff --git a/src/internal.c b/src/internal.c index 3eab81dba..cde4bf2fd 100644 --- a/src/internal.c +++ b/src/internal.c @@ -7761,6 +7761,9 @@ static int DoChannelOpen(WOLFSSH* ssh, else { ChannelUpdatePeer(newChannel, peerChannelId, peerInitialWindowSz, peerMaxPacketSz); + if (ssh->ctx->channelOpenCb) { + ret = ssh->ctx->channelOpenCb(newChannel, ssh->channelOpenCtx); + } if (ssh->channelListSz == 0) ssh->defaultPeerChannelId = peerChannelId; #ifdef WOLFSSH_FWD @@ -7791,16 +7794,18 @@ static int DoChannelOpen(WOLFSSH* ssh, const char *description = NULL; if (fail_reason == OPEN_ADMINISTRATIVELY_PROHIBITED) - description = "Each session cannot have more than one channel open."; + description = "Administratively prohibited."; else if (fail_reason == OPEN_UNKNOWN_CHANNEL_TYPE) description = "Channel type not supported."; else if (fail_reason == OPEN_RESOURCE_SHORTAGE) description = "Not enough resources."; - if (description != NULL) - ret = SendChannelOpenFail(ssh, peerChannelId, fail_reason, description, "en"); + if (description != NULL) { + ret = SendChannelOpenFail(ssh, peerChannelId, + fail_reason, description, "en"); + } else - ret = SendRequestSuccess(ssh, 0); + ret = SendRequestSuccess(ssh, 0); /* XXX Is this right? */ } #ifdef WOLFSSH_FWD @@ -7856,6 +7861,12 @@ static int DoChannelOpenConf(WOLFSSH* ssh, ret = ChannelUpdatePeer(channel, peerChannelId, peerInitialWindowSz, peerMaxPacketSz); + if (ret == WS_SUCCESS) { + if (ssh->ctx->channelOpenConfCb != NULL) { + ret = ssh->ctx->channelOpenConfCb(channel, ssh->channelOpenCtx); + } + } + if (ret == WS_SUCCESS) { ssh->serverState = SERVER_CHANNEL_OPEN_DONE; ssh->defaultPeerChannelId = peerChannelId; @@ -7869,6 +7880,7 @@ static int DoChannelOpenConf(WOLFSSH* ssh, static int DoChannelOpenFail(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) { + WOLFSSH_CHANNEL* channel = NULL; char desc[80]; word32 begin, channelId, reasonId, descSz, langSz; int ret = WS_SUCCESS; @@ -7902,6 +7914,19 @@ static int DoChannelOpenFail(WOLFSSH* ssh, WLOG(WS_LOG_INFO, "description: %s", desc); } + if (ssh->ctx->channelOpenFailCb != NULL) { + channel = ChannelFind(ssh, channelId, WS_CHANNEL_ID_SELF); + + if (channel != NULL) { + ret = ssh->ctx->channelOpenFailCb(channel, ssh->channelOpenCtx); + } + else { + ret = WS_INVALID_CHANID; + } + } + } + + if (ret == WS_SUCCESS) { ret = ChannelRemove(ssh, channelId, WS_CHANNEL_ID_SELF); } @@ -7933,6 +7958,12 @@ static int DoChannelEof(WOLFSSH* ssh, ret = WS_INVALID_CHANID; } + if (ret == WS_SUCCESS) { + if (ssh->ctx->channelEofCb) { + ssh->ctx->channelEofCb(channel, ssh->channelEofCtx); + } + } + if (ret == WS_SUCCESS) { channel->eofRxd = 1; if (!channel->eofTxd) { @@ -7966,6 +7997,12 @@ static int DoChannelClose(WOLFSSH* ssh, ret = WS_INVALID_CHANID; } + if (ret == WS_SUCCESS) { + if (ssh->ctx->channelCloseCb) { + ssh->ctx->channelCloseCb(channel, ssh->channelCloseCtx); + } + } + if (ret == WS_SUCCESS) { if (!channel->closeTxd) { ret = SendChannelClose(ssh, channel->peerChannel); @@ -8239,7 +8276,7 @@ static int DoChannelRequest(WOLFSSH* ssh, word32 typeSz; char type[32]; byte wantReply; - int ret; + int ret, rej = 0; WLOG(WS_LOG_DEBUG, "Entering DoChannelRequest()"); @@ -8268,8 +8305,53 @@ static int DoChannelRequest(WOLFSSH* ssh, WLOG(WS_LOG_DEBUG, " type = %s", type); WLOG(WS_LOG_DEBUG, " wantReply = %u", wantReply); -#ifdef WOLFSSH_TERM - if (WSTRNCMP(type, "pty-req", typeSz) == 0) { + if (WSTRNCMP(type, "env", typeSz) == 0) { + char name[WOLFSSH_MAX_NAMESZ]; + word32 nameSz; + char value[32]; + word32 valueSz; + + name[0] = 0; + value[0] = 0; + nameSz = (word32)sizeof(name); + valueSz = (word32)sizeof(value); + ret = GetString(name, &nameSz, buf, len, &begin); + if (ret == WS_SUCCESS) + ret = GetString(value, &valueSz, buf, len, &begin); + + WLOG(WS_LOG_DEBUG, " %s = %s", name, value); + } + else if (WSTRNCMP(type, "shell", typeSz) == 0) { + channel->sessionType = WOLFSSH_SESSION_SHELL; + if (ssh->ctx->channelReqShellCb) { + rej = ssh->ctx->channelReqShellCb(channel, ssh->channelReqCtx); + } + ssh->clientState = CLIENT_DONE; + } + else if (WSTRNCMP(type, "exec", typeSz) == 0) { + ret = GetStringAlloc(ssh->ctx->heap, &channel->command, + buf, len, &begin); + channel->sessionType = WOLFSSH_SESSION_EXEC; + if (ssh->ctx->channelReqExecCb) { + rej = ssh->ctx->channelReqExecCb(channel, ssh->channelReqCtx); + } + ssh->clientState = CLIENT_DONE; + + WLOG(WS_LOG_DEBUG, " command = %s", channel->command); + } + else if (WSTRNCMP(type, "subsystem", typeSz) == 0) { + ret = GetStringAlloc(ssh->ctx->heap, &channel->command, + buf, len, &begin); + channel->sessionType = WOLFSSH_SESSION_SUBSYSTEM; + if (ssh->ctx->channelReqSubsysCb) { + rej = ssh->ctx->channelReqSubsysCb(channel, ssh->channelReqCtx); + } + ssh->clientState = CLIENT_DONE; + + WLOG(WS_LOG_DEBUG, " subsystem = %s", channel->command); + } + #ifdef WOLFSSH_TERM + else if (WSTRNCMP(type, "pty-req", typeSz) == 0) { char term[32]; const byte* modes; word32 termSz, modesSz = 0; @@ -8314,54 +8396,8 @@ static int DoChannelRequest(WOLFSSH* ssh, } } } - else -#endif /* WOLFSSH_TERM */ - if (WSTRNCMP(type, "env", typeSz) == 0) { - char name[WOLFSSH_MAX_NAMESZ]; - word32 nameSz; - char value[32]; - word32 valueSz; - - name[0] = 0; - value[0] = 0; - nameSz = (word32)sizeof(name); - valueSz = (word32)sizeof(value); - ret = GetString(name, &nameSz, buf, len, &begin); - if (ret == WS_SUCCESS) - ret = GetString(value, &valueSz, buf, len, &begin); - - WLOG(WS_LOG_DEBUG, " %s = %s", name, value); - } - else if (WSTRNCMP(type, "shell", typeSz) == 0) { - channel->sessionType = WOLFSSH_SESSION_SHELL; - ssh->clientState = CLIENT_DONE; - } - else if (WSTRNCMP(type, "exec", typeSz) == 0) { - ret = GetStringAlloc(ssh->ctx->heap, &channel->command, - buf, len, &begin); - channel->sessionType = WOLFSSH_SESSION_EXEC; - ssh->clientState = CLIENT_DONE; - - WLOG(WS_LOG_DEBUG, " command = %s", channel->command); - } - else if (WSTRNCMP(type, "subsystem", typeSz) == 0) { - ret = GetStringAlloc(ssh->ctx->heap, &channel->command, - buf, len, &begin); - channel->sessionType = WOLFSSH_SESSION_SUBSYSTEM; - ssh->clientState = CLIENT_DONE; - - WLOG(WS_LOG_DEBUG, " subsystem = %s", channel->command); - } -#ifdef WOLFSSH_AGENT - else if (WSTRNCMP(type, "auth-agent-req@openssh.com", typeSz) == 0) { - WLOG(WS_LOG_AGENT, " ssh-agent"); - if (ssh->ctx->agentCb != NULL) - ssh->useAgent = 1; - else - WLOG(WS_LOG_AGENT, "Agent callback not set, not using."); - } -#endif /* WOLFSSH_AGENT */ -#if defined(WOLFSSH_SHELL) && defined(WOLFSSH_TERM) + #endif /* WOLFSSH_TERM */ + #if defined(WOLFSSH_SHELL) && defined(WOLFSSH_TERM) else if (WSTRNCMP(type, "window-change", typeSz) == 0) { word32 widthChar, heightRows, widthPixels, heightPixels; @@ -8391,8 +8427,8 @@ static int DoChannelRequest(WOLFSSH* ssh, } } } -#endif /* WOLFSSH_SHELL && WOLFSSH_TERM */ -#if defined(WOLFSSH_TERM) || defined(WOLFSSH_SHELL) + #endif /* WOLFSSH_SHELL && WOLFSSH_TERM */ + #if defined(WOLFSSH_TERM) || defined(WOLFSSH_SHELL) else if (WSTRNCMP(type, "exit-status", typeSz) == 0) { ret = GetUint32(&ssh->exitStatus, buf, len, &begin); WLOG(WS_LOG_AGENT, "Got exit status %u.", ssh->exitStatus); @@ -8425,16 +8461,30 @@ static int DoChannelRequest(WOLFSSH* ssh, ret = GetString(sig, &sigSz, buf, len, &begin); } } -#endif + #endif /* WOLFSSH_TERM or WOLFSSH_SHELL */ + #ifdef WOLFSSH_AGENT + else if (WSTRNCMP(type, "auth-agent-req@openssh.com", typeSz) == 0) { + WLOG(WS_LOG_AGENT, " ssh-agent"); + if (ssh->ctx->agentCb != NULL) + ssh->useAgent = 1; + else + WLOG(WS_LOG_AGENT, "Agent callback not set, not using."); + } + #endif /* WOLFSSH_AGENT */ } - if (ret == WS_SUCCESS) + if (ret == WS_SUCCESS) { *idx = len; + } if (wantReply) { int replyRet; - replyRet = SendChannelSuccess(ssh, channelId, (ret == WS_SUCCESS)); + if (rej) { + WLOG(WS_LOG_DEBUG, "Callback rejecting channel request."); + } + replyRet = SendChannelSuccess(ssh, channelId, + (ret == WS_SUCCESS && !rej)); if (replyRet != WS_SUCCESS) ret = replyRet; } diff --git a/src/ssh.c b/src/ssh.c index 563e2d421..6e67d0ac3 100644 --- a/src/ssh.c +++ b/src/ssh.c @@ -3049,6 +3049,230 @@ void wolfSSH_SetKeyingCompletionCbCtx(WOLFSSH* ssh, void* ctx) } +WS_SessionType wolfSSH_ChannelGetSessionType(const WOLFSSH_CHANNEL* channel) +{ + WS_SessionType type = WOLFSSH_SESSION_UNKNOWN; + + WLOG(WS_LOG_DEBUG, "Entering wolfSSH_ChannelGetType()"); + + if (channel) { + type = (WS_SessionType)channel->sessionType; + } + + return type; +} + + +const char* wolfSSH_ChannelGetSessionCommand(const WOLFSSH_CHANNEL* channel) +{ + const char* cmd = NULL; + + WLOG(WS_LOG_DEBUG, "Entering wolfSSH_ChannelGetCommand()"); + + if (channel) { + cmd = channel->command; + } + + return cmd; +} + + +int wolfSSH_CTX_SetChannelOpenCb(WOLFSSH_CTX* ctx, WS_CallbackChannelOpen cb) +{ + int ret = WS_SSH_CTX_NULL_E; + + if (ctx != NULL) { + ctx->channelOpenCb = cb; + ret = WS_SUCCESS; + } + + return ret; +} + + +int wolfSSH_CTX_SetChannelOpenRespCb(WOLFSSH_CTX* ctx, + WS_CallbackChannelOpen confCb, WS_CallbackChannelOpen failCb) +{ + int ret = WS_SSH_CTX_NULL_E; + + if (ctx != NULL) { + ctx->channelOpenConfCb = confCb; + ctx->channelOpenFailCb = failCb; + ret = WS_SUCCESS; + } + + return ret; +} + + +int wolfSSH_CTX_SetChannelReqShellCb(WOLFSSH_CTX* ctx, + WS_CallbackChannelReq cb) +{ + int ret = WS_SSH_CTX_NULL_E; + + if (ctx != NULL) { + ctx->channelReqShellCb = cb; + ret = WS_SUCCESS; + } + + return ret; +} + + +int wolfSSH_CTX_SetChannelReqExecCb(WOLFSSH_CTX* ctx, + WS_CallbackChannelReq cb) +{ + int ret = WS_SSH_CTX_NULL_E; + + if (ctx != NULL) { + ctx->channelReqExecCb = cb; + ret = WS_SUCCESS; + } + + return ret; +} + + +int wolfSSH_CTX_SetChannelReqSubsysCb(WOLFSSH_CTX* ctx, + WS_CallbackChannelReq cb) +{ + int ret = WS_SSH_CTX_NULL_E; + + if (ctx != NULL) { + ctx->channelReqSubsysCb = cb; + ret = WS_SUCCESS; + } + + return ret; +} + + +int wolfSSH_SetChannelOpenCtx(WOLFSSH* ssh, void* ctx) +{ + int ret = WS_SSH_NULL_E; + + if (ssh != NULL) { + ssh->channelOpenCtx = ctx; + ret = WS_SUCCESS; + } + + return ret; +} + + +void* wolfSSH_GetChannelOpenCtx(WOLFSSH* ssh) +{ + void* ctx = NULL; + + if (ssh != NULL) { + ctx = ssh->channelOpenCtx; + } + + return ctx; +} + + +int wolfSSH_SetChannelReqCtx(WOLFSSH* ssh, void* ctx) +{ + int ret = WS_SSH_NULL_E; + + if (ssh != NULL) { + ssh->channelReqCtx = ctx; + ret = WS_SUCCESS; + } + + return ret; +} + + +void* wolfSSH_GetChannelReqCtx(WOLFSSH* ssh) +{ + void* ctx = NULL; + + if (ssh != NULL) { + ctx = ssh->channelReqCtx; + } + + return ctx; +} + + +int wolfSSH_CTX_SetChannelEofCb(WOLFSSH_CTX* ctx, WS_CallbackChannelEof cb) +{ + int ret = WS_SSH_CTX_NULL_E; + + if (ctx != NULL) { + ctx->channelEofCb = cb; + ret = WS_SUCCESS; + } + + return ret; +} + + +int wolfSSH_SetChannelEofCtx(WOLFSSH* ssh, void* ctx) +{ + int ret = WS_SSH_NULL_E; + + if (ssh != NULL) { + ssh->channelEofCtx = ctx; + ret = WS_SUCCESS; + } + + return ret; +} + + +void* wolfSSH_GetChannelEofCtx(WOLFSSH* ssh) +{ + void* ctx = NULL; + + if (ssh != NULL) { + ctx = ssh->channelEofCtx; + } + + return ctx; +} + + +int wolfSSH_CTX_SetChannelCloseCb(WOLFSSH_CTX* ctx, WS_CallbackChannelClose cb) +{ + int ret = WS_SSH_CTX_NULL_E; + + if (ctx != NULL) { + ctx->channelCloseCb = cb; + ret = WS_SUCCESS; + } + + return ret; +} + + +int wolfSSH_SetChannelCloseCtx(WOLFSSH* ssh, void* ctx) +{ + int ret = WS_SSH_NULL_E; + + if (ssh != NULL) { + ssh->channelCloseCtx = ctx; + ret = WS_SUCCESS; + } + + return ret; +} + + +void* wolfSSH_GetChannelCloseCtx(WOLFSSH* ssh) +{ + void* ctx = NULL; + + if (ssh != NULL) { + ctx = ssh->channelCloseCtx; + } + + return ctx; +} + + #if (defined(WOLFSSH_SFTP) || defined(WOLFSSH_SCP)) && \ !defined(NO_WOLFSSH_SERVER) diff --git a/wolfssh/internal.h b/wolfssh/internal.h index 680555de6..2c26c8187 100644 --- a/wolfssh/internal.h +++ b/wolfssh/internal.h @@ -498,6 +498,14 @@ struct WOLFSSH_CTX { WS_CallbackGlobalReq globalReqCb; /* Global Request Callback */ WS_CallbackReqSuccess reqSuccessCb; /* Global Request Success Callback */ WS_CallbackReqSuccess reqFailureCb; /* Global Request Failure Callback */ + WS_CallbackChannelOpen channelOpenCb; /* Channel Open Requested */ + WS_CallbackChannelOpen channelOpenConfCb; /* Channel Open Confirm */ + WS_CallbackChannelOpen channelOpenFailCb; /* Channel Open Fail */ + WS_CallbackChannelReq channelReqShellCb; /* Channel Request "Shell" */ + WS_CallbackChannelReq channelReqExecCb; /* Channel Request "Exec" */ + WS_CallbackChannelReq channelReqSubsysCb; /* Channel Request "Subsystem" */ + WS_CallbackChannelEof channelEofCb; /* Channel Eof Callback */ + WS_CallbackChannelClose channelCloseCb; /* Channel Close Callback */ #ifdef WOLFSSH_SCP WS_CallbackScpRecv scpRecvCb; /* SCP receive callback */ WS_CallbackScpSend scpSendCb; /* SCP send callback */ @@ -658,10 +666,14 @@ struct WOLFSSH { word32 rxCount; word32 highwaterMark; byte highwaterFlag; /* Set when highwater CB called */ - void* highwaterCtx; + void* highwaterCtx; /* Highwater CB context */ void* globalReqCtx; /* Global Request CB context */ void* reqSuccessCtx; /* Global Request Sucess CB context */ void* reqFailureCtx; /* Global Request Failure CB context */ + void* channelOpenCtx; /* Channel Open CB context */ + void* channelReqCtx; /* Channel Request CB context */ + void* channelEofCtx; /* Channel EOF CB context */ + void* channelCloseCtx; /* Channel Close CB context */ void* fs; /* File system handle */ word32 curSz; word32 seq; diff --git a/wolfssh/ssh.h b/wolfssh/ssh.h index caee02547..8f6a2a115 100644 --- a/wolfssh/ssh.h +++ b/wolfssh/ssh.h @@ -162,6 +162,15 @@ WOLFSSH_API void wolfSSH_SetKeyingCompletionCbCtx(WOLFSSH*, #define WS_CHANNEL_ID_PEER 1 +typedef enum { + WOLFSSH_SESSION_UNKNOWN = 0, + WOLFSSH_SESSION_SHELL, + WOLFSSH_SESSION_EXEC, + WOLFSSH_SESSION_SUBSYSTEM, + WOLFSSH_SESSION_TERMINAL, +} WS_SessionType; + + typedef enum WS_FwdCbAction { WOLFSSH_FWD_LOCAL_SETUP, WOLFSSH_FWD_LOCAL_CLEANUP, @@ -209,7 +218,41 @@ WOLFSSH_API int wolfSSH_ChannelRead(WOLFSSH_CHANNEL*, byte*, word32); WOLFSSH_API int wolfSSH_ChannelSend(WOLFSSH_CHANNEL*, const byte*, word32); WOLFSSH_API int wolfSSH_ChannelExit(WOLFSSH_CHANNEL*); WOLFSSH_API int wolfSSH_ChannelGetEof(WOLFSSH_CHANNEL*); - +WOLFSSH_API WS_SessionType wolfSSH_ChannelGetSessionType( + const WOLFSSH_CHANNEL* channel); +WOLFSSH_API const char* wolfSSH_ChannelGetSessionCommand( + const WOLFSSH_CHANNEL* channel); + +/* Channel callbacks */ +typedef int (*WS_CallbackChannelOpen)(WOLFSSH_CHANNEL* channel, void* ctx); +WOLFSSH_API int wolfSSH_CTX_SetChannelOpenCb(WOLFSSH_CTX* ctx, + WS_CallbackChannelOpen cb); +WOLFSSH_API int wolfSSH_CTX_SetChannelOpenRespCb(WOLFSSH_CTX* ctx, + WS_CallbackChannelOpen confCb, WS_CallbackChannelOpen failCb); +WOLFSSH_API int wolfSSH_SetChannelOpenCtx(WOLFSSH* ssh, void* ctx); +WOLFSSH_API void* wolfSSH_GetChannelOpenCtx(WOLFSSH* ssh); + +typedef int (*WS_CallbackChannelReq)(WOLFSSH_CHANNEL* channel, void* ctx); +WOLFSSH_API int wolfSSH_CTX_SetChannelReqShellCb(WOLFSSH_CTX* ctx, + WS_CallbackChannelReq cb); +WOLFSSH_API int wolfSSH_CTX_SetChannelReqExecCb(WOLFSSH_CTX* ctx, + WS_CallbackChannelReq cb); +WOLFSSH_API int wolfSSH_CTX_SetChannelReqSubsysCb(WOLFSSH_CTX* ctx, + WS_CallbackChannelReq cb); +WOLFSSH_API int wolfSSH_SetChannelReqCtx(WOLFSSH* ssh, void* ctx); +WOLFSSH_API void* wolfSSH_GetChannelReqCtx(WOLFSSH* ssh); + +typedef int (*WS_CallbackChannelEof)(WOLFSSH_CHANNEL* channel, void* ctx); +WOLFSSH_API int wolfSSH_CTX_SetChannelEofCb(WOLFSSH_CTX* ctx, + WS_CallbackChannelEof cb); +WOLFSSH_API int wolfSSH_SetChannelEofCtx(WOLFSSH* ssh, void* ctx); +WOLFSSH_API void* wolfSSH_GetChannelEofCtx(WOLFSSH* ssh); + +typedef int (*WS_CallbackChannelClose)(WOLFSSH_CHANNEL* channel, void* ctx); +WOLFSSH_API int wolfSSH_CTX_SetChannelCloseCb(WOLFSSH_CTX* ctx, + WS_CallbackChannelClose cb); +WOLFSSH_API int wolfSSH_SetChannelCloseCtx(WOLFSSH* ssh, void* ctx); +WOLFSSH_API void* wolfSSH_GetChannelCloseCtx(WOLFSSH* ssh); WOLFSSH_API int wolfSSH_get_error(const WOLFSSH*); WOLFSSH_API const char* wolfSSH_get_error_name(const WOLFSSH*); @@ -342,13 +385,6 @@ WOLFSSH_API int wolfSSH_KDF(byte, byte, byte*, word32, const byte*, word32, WOLFSSH_API int wolfSSH_ConvertConsole(WOLFSSH*, WOLFSSH_HANDLE, byte*, word32); #endif -typedef enum { - WOLFSSH_SESSION_UNKNOWN = 0, - WOLFSSH_SESSION_SHELL, - WOLFSSH_SESSION_EXEC, - WOLFSSH_SESSION_SUBSYSTEM, - WOLFSSH_SESSION_TERMINAL, -} WS_SessionType; WOLFSSH_API int wolfSSH_DoModes(const byte* modes, word32 modesSz, int fd); WOLFSSH_API WS_SessionType wolfSSH_GetSessionType(const WOLFSSH*);