@@ -11800,6 +11800,56 @@ static int DoGlobalRequestFwd(WOLFSSH* ssh,
1180011800}
1180111801#endif
1180211802
11803+ /* Puts a global request to the generic callback, which sees the name and
11804+ * the type-specific part to parse itself. Returns 1 when the callback
11805+ * settled the request, with any wanted reply sent and *ret carrying the
11806+ * result, or 0 to leave it to the built-in handling. */
11807+ static int DoGlobalRequestAny(WOLFSSH* ssh, const char* name, int globReqId,
11808+ byte* buf, word32 len, word32 begin, byte wantReply, int* ret)
11809+ {
11810+ int decision, success;
11811+
11812+ if (ssh->ctx->globalReqAnyCb == NULL) {
11813+ return 0;
11814+ }
11815+
11816+ decision = ssh->ctx->globalReqAnyCb(ssh, name, buf + begin, len - begin,
11817+ wantReply, ssh->globalReqCtx);
11818+ if (decision != WOLFSSH_REQ_ACCEPT && decision != WOLFSSH_REQ_REJECT) {
11819+ return 0;
11820+ }
11821+ success = (decision == WOLFSSH_REQ_ACCEPT);
11822+
11823+ #ifdef WOLFSSH_FWD
11824+ /* RFC 4254 7.1: a port-0 request is answered with the port bound,
11825+ * which only the forward callback can report. */
11826+ if (success && globReqId == ID_GLOBREQ_TCPIP_FWD) {
11827+ const byte* bindAddr;
11828+ word32 bindAddrSz, bindPort = 0, peek = begin;
11829+
11830+ if (GetStringRef(&bindAddrSz, &bindAddr, buf, len, &peek)
11831+ != WS_SUCCESS
11832+ || GetUint32(&bindPort, buf, len, &peek) != WS_SUCCESS
11833+ || bindPort == 0) {
11834+ WLOG(WS_LOG_WARN, "DGR: a port-0 forward needs the forward "
11835+ "callback to bind it; rejecting");
11836+ success = 0;
11837+ }
11838+ }
11839+ #else
11840+ (void)globReqId;
11841+ #endif
11842+
11843+ WLOG(WS_LOG_DEBUG, "DGR: global request callback %s",
11844+ success ? "granted" : "refused");
11845+ if (wantReply) {
11846+ *ret = SendRequestSuccess(ssh, success);
11847+ }
11848+
11849+ return 1;
11850+ }
11851+
11852+
1180311853static int DoGlobalRequest(WOLFSSH* ssh,
1180411854 byte* buf, word32 len, word32* idx)
1180511855{
@@ -11846,31 +11896,37 @@ static int DoGlobalRequest(WOLFSSH* ssh,
1184611896 }
1184711897 else
1184811898#endif
11849- switch (globReqId) {
11899+ if (!DoGlobalRequestAny(ssh, name, globReqId, buf, len, begin,
11900+ wantReply, &ret)) {
11901+ switch (globReqId) {
1185011902#ifdef WOLFSSH_FWD
11851- case ID_GLOBREQ_TCPIP_FWD:
11852- ret = DoGlobalRequestFwd(ssh, buf, len, &begin, wantReply, 0);
11853- wantReply = 0;
11854- break;
11855- case ID_GLOBREQ_TCPIP_FWD_CANCEL:
11856- ret = DoGlobalRequestFwd(ssh, buf, len, &begin, wantReply, 1);
11857- wantReply = 0;
11858- break;
11903+ case ID_GLOBREQ_TCPIP_FWD:
11904+ ret = DoGlobalRequestFwd(ssh, buf, len, &begin,
11905+ wantReply, 0);
11906+ wantReply = 0;
11907+ break;
11908+ case ID_GLOBREQ_TCPIP_FWD_CANCEL:
11909+ ret = DoGlobalRequestFwd(ssh, buf, len, &begin,
11910+ wantReply, 1);
11911+ wantReply = 0;
11912+ break;
1185911913#endif
11860- default:
11861- if (ssh->ctx->globalReqCb != NULL) {
11862- ret = ssh->ctx->globalReqCb(ssh, name, nameSz, wantReply ,
11863- (void *)ssh->globalReqCtx);
11914+ default:
11915+ if (ssh->ctx->globalReqCb != NULL) {
11916+ ret = ssh->ctx->globalReqCb(ssh, name, nameSz,
11917+ wantReply, (void *)ssh->globalReqCtx);
1186411918
11865- if (wantReply) {
11866- ret = SendRequestSuccess(ssh, (ret == WS_SUCCESS));
11919+ if (wantReply) {
11920+ ret = SendRequestSuccess(ssh,
11921+ (ret == WS_SUCCESS));
11922+ }
1186711923 }
11868- }
11869- else if (wantReply)
11870- ret = SendRequestSuccess(ssh, 0);
11871- /* response SSH_MSG_REQUEST_FAILURE to Keep-Alive.
11872- * IETF:draft-ssh-global-requests */
11873- break;
11924+ else if (wantReply)
11925+ ret = SendRequestSuccess(ssh, 0);
11926+ /* response SSH_MSG_REQUEST_FAILURE to Keep-Alive.
11927+ * IETF:draft-ssh-global-requests */
11928+ break;
11929+ }
1187411930 }
1187511931 }
1187611932
@@ -12672,9 +12728,10 @@ static void SetTerminalSize(WOLFSSH* ssh, word32 widthChar, word32 heightRows,
1267212728 * kept only if it accepts; a refused request leaves the channel as it was
1267312729 * and the accept loop still waiting, so nothing serves a session the
1267412730 * application turned down. Without a callback the request is accepted,
12675- * unless the application drives its own channels. */
12731+ * unless the application drives its own channels. A request the generic
12732+ * callback already granted asks no callback. */
1267612733static int DoChannelRequestSession(WOLFSSH* ssh, WOLFSSH_CHANNEL* channel,
12677- byte sessionType, WS_CallbackChannelReq cb,
12734+ byte sessionType, WS_CallbackChannelReq cb, int granted,
1267812735 byte* buf, word32 len, word32* idx, int* rej)
1267912736{
1268012737 char* prevCommand = NULL;
@@ -12694,7 +12751,10 @@ static int DoChannelRequestSession(WOLFSSH* ssh, WOLFSSH_CHANNEL* channel,
1269412751
1269512752 if (ret == WS_SUCCESS) {
1269612753 channel->sessionType = sessionType;
12697- if (cb != NULL) {
12754+ if (granted) {
12755+ *rej = 0;
12756+ }
12757+ else if (cb != NULL) {
1269812758 *rej = cb(channel, ssh->channelReqCtx);
1269912759 }
1270012760 else {
@@ -12731,7 +12791,7 @@ static int DoChannelRequest(WOLFSSH* ssh,
1273112791 word32 typeSz;
1273212792 char type[32];
1273312793 byte wantReply;
12734- int ret, rej = 0;
12794+ int ret, rej = 0, granted = 0 ;
1273512795
1273612796 WLOG(WS_LOG_DEBUG, "Entering DoChannelRequest()");
1273712797
@@ -12760,6 +12820,23 @@ static int DoChannelRequest(WOLFSSH* ssh,
1276012820 WLOG(WS_LOG_DEBUG, " type = %s", type);
1276112821 WLOG(WS_LOG_DEBUG, " wantReply = %u", wantReply);
1276212822
12823+ /* The generic callback sees every request first, with the
12824+ * type-specific part to parse itself. A refusal skips the handling
12825+ * below; a grant runs it with the decision already made. */
12826+ if (ssh->ctx->channelReqAnyCb != NULL) {
12827+ int decision = ssh->ctx->channelReqAnyCb(channel, type,
12828+ buf + begin, len - begin, ssh->channelReqCtx);
12829+ if (decision == WOLFSSH_REQ_REJECT) {
12830+ WLOG(WS_LOG_DEBUG, " channel request callback refused.");
12831+ rej = 1;
12832+ }
12833+ else if (decision == WOLFSSH_REQ_ACCEPT) {
12834+ granted = 1;
12835+ }
12836+ }
12837+ }
12838+
12839+ if (ret == WS_SUCCESS && !rej) {
1276312840 if (ChannelRequestIs(type, typeSz, "env")) {
1276412841 char name[WOLFSSH_MAX_NAMESZ];
1276512842 word32 nameSz;
@@ -12778,16 +12855,18 @@ static int DoChannelRequest(WOLFSSH* ssh,
1277812855 }
1277912856 else if (ChannelRequestIs(type, typeSz, "shell")) {
1278012857 ret = DoChannelRequestSession(ssh, channel, WOLFSSH_SESSION_SHELL,
12781- ssh->ctx->channelReqShellCb, buf, len, &begin, &rej);
12858+ ssh->ctx->channelReqShellCb, granted, buf, len, &begin,
12859+ &rej);
1278212860 }
1278312861 else if (ChannelRequestIs(type, typeSz, "exec")) {
1278412862 ret = DoChannelRequestSession(ssh, channel, WOLFSSH_SESSION_EXEC,
12785- ssh->ctx->channelReqExecCb, buf, len, &begin, &rej);
12863+ ssh->ctx->channelReqExecCb, granted, buf, len, &begin,
12864+ &rej);
1278612865 }
1278712866 else if (ChannelRequestIs(type, typeSz, "subsystem")) {
1278812867 ret = DoChannelRequestSession(ssh, channel,
1278912868 WOLFSSH_SESSION_SUBSYSTEM, ssh->ctx->channelReqSubsysCb,
12790- buf, len, &begin, &rej);
12869+ granted, buf, len, &begin, &rej);
1279112870 }
1279212871 #ifdef WOLFSSH_TERM
1279312872 else if (ChannelRequestIs(type, typeSz, "pty-req")) {
@@ -12912,6 +12991,9 @@ static int DoChannelRequest(WOLFSSH* ssh,
1291212991 WLOG(WS_LOG_AGENT, "Agent callback not set, not using.");
1291312992 }
1291412993 #endif /* WOLFSSH_AGENT */
12994+ else if (granted) {
12995+ WLOG(WS_LOG_DEBUG, " unknown channel request type, granted.");
12996+ }
1291512997 else {
1291612998 WLOG(WS_LOG_DEBUG, " unknown channel request type, rejecting.");
1291712999 rej = 1;
0 commit comments