@@ -11761,6 +11761,56 @@ static int DoGlobalRequestFwd(WOLFSSH* ssh,
1176111761}
1176211762#endif
1176311763
11764+ /* Puts a global request to the generic callback, which sees the name and
11765+ * the type-specific part to parse itself. Returns 1 when the callback
11766+ * settled the request, with any wanted reply sent and *ret carrying the
11767+ * result, or 0 to leave it to the built-in handling. */
11768+ static int DoGlobalRequestAny(WOLFSSH* ssh, const char* name, int globReqId,
11769+ byte* buf, word32 len, word32 begin, byte wantReply, int* ret)
11770+ {
11771+ int decision, success;
11772+
11773+ if (ssh->ctx->globalReqAnyCb == NULL) {
11774+ return 0;
11775+ }
11776+
11777+ decision = ssh->ctx->globalReqAnyCb(ssh, name, buf + begin, len - begin,
11778+ wantReply, ssh->globalReqCtx);
11779+ if (decision != WOLFSSH_REQ_ACCEPT && decision != WOLFSSH_REQ_REJECT) {
11780+ return 0;
11781+ }
11782+ success = (decision == WOLFSSH_REQ_ACCEPT);
11783+
11784+ #ifdef WOLFSSH_FWD
11785+ /* RFC 4254 7.1: a port-0 request is answered with the port bound,
11786+ * which only the forward callback can report. */
11787+ if (success && globReqId == ID_GLOBREQ_TCPIP_FWD) {
11788+ const byte* bindAddr;
11789+ word32 bindAddrSz, bindPort = 0, peek = begin;
11790+
11791+ if (GetStringRef(&bindAddrSz, &bindAddr, buf, len, &peek)
11792+ != WS_SUCCESS
11793+ || GetUint32(&bindPort, buf, len, &peek) != WS_SUCCESS
11794+ || bindPort == 0) {
11795+ WLOG(WS_LOG_WARN, "DGR: a port-0 forward needs the forward "
11796+ "callback to bind it; rejecting");
11797+ success = 0;
11798+ }
11799+ }
11800+ #else
11801+ (void)globReqId;
11802+ #endif
11803+
11804+ WLOG(WS_LOG_DEBUG, "DGR: global request callback %s",
11805+ success ? "granted" : "refused");
11806+ if (wantReply) {
11807+ *ret = SendRequestSuccess(ssh, success);
11808+ }
11809+
11810+ return 1;
11811+ }
11812+
11813+
1176411814static int DoGlobalRequest(WOLFSSH* ssh,
1176511815 byte* buf, word32 len, word32* idx)
1176611816{
@@ -11807,31 +11857,37 @@ static int DoGlobalRequest(WOLFSSH* ssh,
1180711857 }
1180811858 else
1180911859#endif
11810- switch (globReqId) {
11860+ if (!DoGlobalRequestAny(ssh, name, globReqId, buf, len, begin,
11861+ wantReply, &ret)) {
11862+ switch (globReqId) {
1181111863#ifdef WOLFSSH_FWD
11812- case ID_GLOBREQ_TCPIP_FWD:
11813- ret = DoGlobalRequestFwd(ssh, buf, len, &begin, wantReply, 0);
11814- wantReply = 0;
11815- break;
11816- case ID_GLOBREQ_TCPIP_FWD_CANCEL:
11817- ret = DoGlobalRequestFwd(ssh, buf, len, &begin, wantReply, 1);
11818- wantReply = 0;
11819- break;
11864+ case ID_GLOBREQ_TCPIP_FWD:
11865+ ret = DoGlobalRequestFwd(ssh, buf, len, &begin,
11866+ wantReply, 0);
11867+ wantReply = 0;
11868+ break;
11869+ case ID_GLOBREQ_TCPIP_FWD_CANCEL:
11870+ ret = DoGlobalRequestFwd(ssh, buf, len, &begin,
11871+ wantReply, 1);
11872+ wantReply = 0;
11873+ break;
1182011874#endif
11821- default:
11822- if (ssh->ctx->globalReqCb != NULL) {
11823- ret = ssh->ctx->globalReqCb(ssh, name, nameSz, wantReply ,
11824- (void *)ssh->globalReqCtx);
11875+ default:
11876+ if (ssh->ctx->globalReqCb != NULL) {
11877+ ret = ssh->ctx->globalReqCb(ssh, name, nameSz,
11878+ wantReply, (void *)ssh->globalReqCtx);
1182511879
11826- if (wantReply) {
11827- ret = SendRequestSuccess(ssh, (ret == WS_SUCCESS));
11880+ if (wantReply) {
11881+ ret = SendRequestSuccess(ssh,
11882+ (ret == WS_SUCCESS));
11883+ }
1182811884 }
11829- }
11830- else if (wantReply)
11831- ret = SendRequestSuccess(ssh, 0);
11832- /* response SSH_MSG_REQUEST_FAILURE to Keep-Alive.
11833- * IETF:draft-ssh-global-requests */
11834- break;
11885+ else if (wantReply)
11886+ ret = SendRequestSuccess(ssh, 0);
11887+ /* response SSH_MSG_REQUEST_FAILURE to Keep-Alive.
11888+ * IETF:draft-ssh-global-requests */
11889+ break;
11890+ }
1183511891 }
1183611892 }
1183711893
@@ -12622,9 +12678,10 @@ static void SetTerminalSize(WOLFSSH* ssh, word32 widthChar, word32 heightRows,
1262212678 * kept only if it accepts; a refused request leaves the channel as it was
1262312679 * and the accept loop still waiting, so nothing serves a session the
1262412680 * application turned down. Without a callback the request is accepted,
12625- * unless the application drives its own channels. */
12681+ * unless the application drives its own channels. A request the generic
12682+ * callback already granted asks no callback. */
1262612683static int DoChannelRequestSession(WOLFSSH* ssh, WOLFSSH_CHANNEL* channel,
12627- byte sessionType, WS_CallbackChannelReq cb,
12684+ byte sessionType, WS_CallbackChannelReq cb, int granted,
1262812685 byte* buf, word32 len, word32* idx, int* rej)
1262912686{
1263012687 char* prevCommand = NULL;
@@ -12644,7 +12701,10 @@ static int DoChannelRequestSession(WOLFSSH* ssh, WOLFSSH_CHANNEL* channel,
1264412701
1264512702 if (ret == WS_SUCCESS) {
1264612703 channel->sessionType = sessionType;
12647- if (cb != NULL) {
12704+ if (granted) {
12705+ *rej = 0;
12706+ }
12707+ else if (cb != NULL) {
1264812708 *rej = cb(channel, ssh->channelReqCtx);
1264912709 }
1265012710 else {
@@ -12681,7 +12741,7 @@ static int DoChannelRequest(WOLFSSH* ssh,
1268112741 word32 typeSz;
1268212742 char type[32];
1268312743 byte wantReply;
12684- int ret, rej = 0;
12744+ int ret, rej = 0, granted = 0 ;
1268512745
1268612746 WLOG(WS_LOG_DEBUG, "Entering DoChannelRequest()");
1268712747
@@ -12710,6 +12770,23 @@ static int DoChannelRequest(WOLFSSH* ssh,
1271012770 WLOG(WS_LOG_DEBUG, " type = %s", type);
1271112771 WLOG(WS_LOG_DEBUG, " wantReply = %u", wantReply);
1271212772
12773+ /* The generic callback sees every request first, with the
12774+ * type-specific part to parse itself. A refusal skips the handling
12775+ * below; a grant runs it with the decision already made. */
12776+ if (ssh->ctx->channelReqAnyCb != NULL) {
12777+ int decision = ssh->ctx->channelReqAnyCb(channel, type,
12778+ buf + begin, len - begin, ssh->channelReqCtx);
12779+ if (decision == WOLFSSH_REQ_REJECT) {
12780+ WLOG(WS_LOG_DEBUG, " channel request callback refused.");
12781+ rej = 1;
12782+ }
12783+ else if (decision == WOLFSSH_REQ_ACCEPT) {
12784+ granted = 1;
12785+ }
12786+ }
12787+ }
12788+
12789+ if (ret == WS_SUCCESS && !rej) {
1271312790 if (ChannelRequestIs(type, typeSz, "env")) {
1271412791 char name[WOLFSSH_MAX_NAMESZ];
1271512792 word32 nameSz;
@@ -12728,16 +12805,18 @@ static int DoChannelRequest(WOLFSSH* ssh,
1272812805 }
1272912806 else if (ChannelRequestIs(type, typeSz, "shell")) {
1273012807 ret = DoChannelRequestSession(ssh, channel, WOLFSSH_SESSION_SHELL,
12731- ssh->ctx->channelReqShellCb, buf, len, &begin, &rej);
12808+ ssh->ctx->channelReqShellCb, granted, buf, len, &begin,
12809+ &rej);
1273212810 }
1273312811 else if (ChannelRequestIs(type, typeSz, "exec")) {
1273412812 ret = DoChannelRequestSession(ssh, channel, WOLFSSH_SESSION_EXEC,
12735- ssh->ctx->channelReqExecCb, buf, len, &begin, &rej);
12813+ ssh->ctx->channelReqExecCb, granted, buf, len, &begin,
12814+ &rej);
1273612815 }
1273712816 else if (ChannelRequestIs(type, typeSz, "subsystem")) {
1273812817 ret = DoChannelRequestSession(ssh, channel,
1273912818 WOLFSSH_SESSION_SUBSYSTEM, ssh->ctx->channelReqSubsysCb,
12740- buf, len, &begin, &rej);
12819+ granted, buf, len, &begin, &rej);
1274112820 }
1274212821 #ifdef WOLFSSH_TERM
1274312822 else if (ChannelRequestIs(type, typeSz, "pty-req")) {
@@ -12862,6 +12941,9 @@ static int DoChannelRequest(WOLFSSH* ssh,
1286212941 WLOG(WS_LOG_AGENT, "Agent callback not set, not using.");
1286312942 }
1286412943 #endif /* WOLFSSH_AGENT */
12944+ else if (granted) {
12945+ WLOG(WS_LOG_DEBUG, " unknown channel request type, granted.");
12946+ }
1286512947 else {
1286612948 WLOG(WS_LOG_DEBUG, " unknown channel request type, rejecting.");
1286712949 rej = 1;
0 commit comments