ssh_request.c
Go to the documentation of this file.
1 /**
2  * @file ssh_request.c
3  * @brief Global request and channel request handling
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2019-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneSSH Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.4.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL SSH_TRACE_LEVEL
33 
34 //Dependencies
35 #include "ssh/ssh.h"
36 #include "ssh/ssh_request.h"
37 #include "ssh/ssh_channel.h"
38 #include "ssh/ssh_packet.h"
39 #include "ssh/ssh_misc.h"
40 #include "debug.h"
41 
42 //Check SSH stack configuration
43 #if (SSH_SUPPORT == ENABLED)
44 
45 
46 /**
47  * @brief Send SSH_MSG_GLOBAL_REQUEST message
48  * @param[in] connection Pointer to the SSH connection
49  * @param[in] requestName NULL-terminated string containing the request name
50  * @param[in] requestParams Pointer to the request specific parameters
51  * @param[in] wantReply This flag specifies whether a reply is expected
52  * @return Error code
53  **/
54 
56  const char_t *requestName, const void *requestParams, bool_t wantReply)
57 {
58  error_t error;
59  size_t length;
60  uint8_t *message;
61 
62  //Point to the buffer where to format the message
63  message = connection->buffer + SSH_PACKET_HEADER_SIZE;
64 
65  //Format SSH_MSG_GLOBAL_REQUEST message
66  error = sshFormatGlobalRequest(connection, requestName, requestParams,
67  wantReply, message, &length);
68 
69  //Check status code
70  if(!error)
71  {
72  //Debug message
73  TRACE_INFO("Sending SSH_MSG_GLOBAL_REQUEST message (%" PRIuSIZE " bytes)...\r\n", length);
75 
76  //Send message
77  error = sshSendPacket(connection, message, length);
78  }
79 
80  //Check status code
81  if(!error)
82  {
83  //Check whether a reply is expected from the other party
84  if(wantReply)
85  {
86  //The recipient will respond with either SSH_MSG_REQUEST_SUCCESS or
87  //SSH_MSG_REQUEST_FAILURE message
88  connection->requestState = SSH_REQUEST_STATE_PENDING;
89  }
90  else
91  {
92  //The recipient will not respond to the request
93  connection->requestState = SSH_REQUEST_STATE_IDLE;
94  }
95  }
96 
97  //Return status code
98  return error;
99 }
100 
101 
102 /**
103  * @brief Send SSH_MSG_REQUEST_SUCCESS message
104  * @param[in] connection Pointer to the SSH connection
105  * @return Error code
106  **/
107 
109 {
110  error_t error;
111  size_t length;
112  uint8_t *message;
113 
114  //Point to the buffer where to format the message
115  message = connection->buffer + SSH_PACKET_HEADER_SIZE;
116 
117  //Format SSH_MSG_REQUEST_SUCCESS message
118  error = sshFormatRequestSuccess(connection, message, &length);
119 
120  //Check status code
121  if(!error)
122  {
123  //Debug message
124  TRACE_INFO("Sending SSH_MSG_REQUEST_SUCCESS message (%" PRIuSIZE " bytes)...\r\n", length);
126 
127  //Send message
128  error = sshSendPacket(connection, message, length);
129  }
130 
131  //Return status code
132  return error;
133 }
134 
135 
136 /**
137  * @brief Send SSH_MSG_REQUEST_FAILURE message
138  * @param[in] connection Pointer to the SSH connection
139  * @return Error code
140  **/
141 
143 {
144  error_t error;
145  size_t length;
146  uint8_t *message;
147 
148  //Point to the buffer where to format the message
149  message = connection->buffer + SSH_PACKET_HEADER_SIZE;
150 
151  //Format SSH_MSG_REQUEST_FAILURE message
152  error = sshFormatRequestFailure(connection, message, &length);
153 
154  //Check status code
155  if(!error)
156  {
157  //Debug message
158  TRACE_INFO("Sending SSH_MSG_REQUEST_FAILURE message (%" PRIuSIZE " bytes)...\r\n", length);
160 
161  //Send message
162  error = sshSendPacket(connection, message, length);
163  }
164 
165  //Return status code
166  return error;
167 }
168 
169 
170 /**
171  * @brief Send SSH_MSG_CHANNEL_REQUEST message
172  * @param[in] channel Handle referencing an SSH channel
173  * @param[in] requestType NULL-terminated string containing the request type
174  * @param[in] requestParams Pointer to the request specific parameters
175  * @param[in] wantReply This flag specifies whether a reply is expected
176  * @return Error code
177  **/
178 
179 error_t sshSendChannelRequest(SshChannel *channel, const char_t *requestType,
180  const void *requestParams, bool_t wantReply)
181 {
182  error_t error;
183  size_t length;
184  uint8_t *message;
185  SshConnection *connection;
186 
187  //Point to the SSH connection
188  connection = channel->connection;
189 
190  //Point to the buffer where to format the message
191  message = connection->buffer + SSH_PACKET_HEADER_SIZE;
192 
193  //Format SSH_MSG_CHANNEL_REQUEST message
194  error = sshFormatChannelRequest(channel, requestType, requestParams,
195  wantReply, message, &length);
196 
197  //Check status code
198  if(!error)
199  {
200  //Debug message
201  TRACE_INFO("Sending SSH_MSG_CHANNEL_REQUEST message (%" PRIuSIZE " bytes)...\r\n", length);
203 
204  //Send message
205  error = sshSendPacket(connection, message, length);
206  }
207 
208  //Check status code
209  if(!error)
210  {
211  //Check whether a reply is expected from the other party
212  if(wantReply)
213  {
214  //The recipient will respond with either SSH_MSG_CHANNEL_SUCCESS or
215  //SSH_MSG_CHANNEL_FAILURE message
216  channel->requestState = SSH_REQUEST_STATE_PENDING;
217  }
218  else
219  {
220  //The recipient will not respond to the request
221  channel->requestState = SSH_REQUEST_STATE_IDLE;
222  }
223  }
224 
225  //Return status code
226  return error;
227 }
228 
229 
230 /**
231  * @brief Send SSH_MSG_CHANNEL_SUCCESS message
232  * @param[in] channel Handle referencing an SSH channel
233  * @return Error code
234  **/
235 
237 {
238  error_t error;
239  size_t length;
240  uint8_t *message;
241  SshConnection *connection;
242 
243  //Point to the SSH connection
244  connection = channel->connection;
245 
246  //Point to the buffer where to format the message
247  message = connection->buffer + SSH_PACKET_HEADER_SIZE;
248 
249  //Format SSH_MSG_CHANNEL_SUCCESS message
250  error = sshFormatChannelSuccess(channel, message, &length);
251 
252  //Check status code
253  if(!error)
254  {
255  //Debug message
256  TRACE_INFO("Sending SSH_MSG_CHANNEL_SUCCESS message (%" PRIuSIZE " bytes)...\r\n", length);
258 
259  //Send message
260  error = sshSendPacket(connection, message, length);
261  }
262 
263  //Check status code
264  if(!error)
265  {
266  //An SSH_MSG_CHANNEL_SUCCESS message has been successfully sent
267  channel->channelSuccessSent = TRUE;
268  }
269 
270  //Return status code
271  return error;
272 }
273 
274 
275 /**
276  * @brief Send SSH_MSG_CHANNEL_FAILURE message
277  * @param[in] channel Handle referencing an SSH channel
278  * @return Error code
279  **/
280 
282 {
283  error_t error;
284  size_t length;
285  uint8_t *message;
286  SshConnection *connection;
287 
288  //Point to the SSH connection
289  connection = channel->connection;
290 
291  //Point to the buffer where to format the message
292  message = connection->buffer + SSH_PACKET_HEADER_SIZE;
293 
294  //Format SSH_MSG_CHANNEL_FAILURE message
295  error = sshFormatChannelFailure(channel, message, &length);
296 
297  //Check status code
298  if(!error)
299  {
300  //Debug message
301  TRACE_INFO("Sending SSH_MSG_CHANNEL_FAILURE message (%" PRIuSIZE " bytes)...\r\n", length);
303 
304  //Send message
305  error = sshSendPacket(connection, message, length);
306  }
307 
308  //Return status code
309  return error;
310 }
311 
312 
313 /**
314  * @brief Format SSH_MSG_GLOBAL_REQUEST message
315  * @param[in] connection Pointer to the SSH connection
316  * @param[in] requestName NULL-terminated string containing the request name
317  * @param[in] requestParams Pointer to the request specific parameters
318  * @param[in] wantReply This flag specifies whether a reply is expected
319  * @param[out] p Buffer where to format the message
320  * @param[out] length Length of the resulting message, in bytes
321  * @return Error code
322  **/
323 
325  const char_t *requestName, const void *requestParams, bool_t wantReply,
326  uint8_t *p, size_t *length)
327 {
328  error_t error;
329  size_t n;
330 
331  //Total length of the message
332  *length = 0;
333 
334  //Set message type
336 
337  //Point to the first field of the message
338  p += sizeof(uint8_t);
339  *length += sizeof(uint8_t);
340 
341  //Set request name
342  error = sshFormatString(requestName, p, &n);
343  //Any error to report?
344  if(error)
345  return error;
346 
347  //Point to the next field
348  p += n;
349  *length += n;
350 
351  //Set want_reply boolean
352  p[0] = wantReply ? TRUE : FALSE;
353 
354  //Point to the next field
355  p += sizeof(uint8_t);
356  *length += sizeof(uint8_t);
357 
358  //Check request type
359  if(!osStrcmp(requestName, "tcpip-forward"))
360  {
361  //Format "tcpip-forward" request specific data
362  error = sshFormatTcpIpFwdParams(requestParams, p, &n);
363  }
364  else if(!osStrcmp(requestName, "cancel-tcpip-forward"))
365  {
366  //Format "cancel-tcpip-forward" request specific data
367  error = sshFormatCancelTcpIpFwdParams(requestParams, p, &n);
368  }
369  else if(!osStrcmp(requestName, "elevation"))
370  {
371  //Format "elevation" request specific data
372  error = sshFormatElevationParams(requestParams, p, &n);
373  }
374  else
375  {
376  //Report an error
378  }
379 
380  //Check status code
381  if(!error)
382  {
383  //Total length of the message
384  *length += n;
385  }
386 
387  //Return status code
388  return error;
389 }
390 
391 
392 /**
393  * @brief Format "tcpip-forward" global request parameters
394  * @param[in] params Pointer to the request specific parameters
395  * @param[out] p Output stream where to write the request specific data
396  * @param[out] written Total number of bytes that have been written
397  * @return Error code
398  **/
399 
401  uint8_t *p, size_t *written)
402 {
403  error_t error;
404  size_t n;
405 
406  //Check parameters
407  if(params == NULL)
409 
410  //Total length of the request specific data
411  *written = 0;
412 
413  //The 'address to bind' field specifies the IP address on which connections
414  //for forwarding are to be accepted
415  error = sshFormatBinaryString(params->addrToBind.value,
416  params->addrToBind.length, p, &n);
417  //Any error to report?
418  if(error)
419  return error;
420 
421  //Point to the next field
422  p += n;
423  *written += n;
424 
425  //The 'port number to bind' field specifies the port on which connections
426  //for forwarding are to be accepted
427  STORE32BE(params->portNumToBind, p);
428 
429  //Total number of bytes that have been written
430  *written += sizeof(uint32_t);
431 
432  //Successful processing
433  return NO_ERROR;
434 }
435 
436 
437 /**
438  * @brief Format "cancel-tcpip-forward" global request parameters
439  * @param[in] params Pointer to the request specific parameters
440  * @param[out] p Output stream where to write the request specific data
441  * @param[out] written Total number of bytes that have been written
442  * @return Error code
443  **/
444 
446  uint8_t *p, size_t *written)
447 {
448  error_t error;
449  size_t n;
450 
451  //Check parameters
452  if(params == NULL)
454 
455  //Total length of the request specific data
456  *written = 0;
457 
458  //Set 'address to bind' field
459  error = sshFormatBinaryString(params->addrToBind.value,
460  params->addrToBind.length, p, &n);
461  //Any error to report?
462  if(error)
463  return error;
464 
465  //Point to the next field
466  p += n;
467  *written += n;
468 
469  //Set 'port number to bind' field
470  STORE32BE(params->portNumToBind, p);
471 
472  //Total number of bytes that have been written
473  *written += sizeof(uint32_t);
474 
475  //Successful processing
476  return NO_ERROR;
477 }
478 
479 
480 /**
481  * @brief Format "elevation" global request parameters
482  * @param[in] params Pointer to the request specific parameters
483  * @param[out] p Output stream where to write the request specific data
484  * @param[out] written Total number of bytes that have been written
485  * @return Error code
486  **/
487 
489  uint8_t *p, size_t *written)
490 {
491  //Check parameters
492  if(params == NULL)
494 
495  //The server use the 'elevation performed' field to indicates to the client
496  //whether elevation was done
497  p[0] = params->elevationPerformed ? TRUE : FALSE;
498 
499  //Total number of bytes that have been written
500  *written = sizeof(uint8_t);
501 
502  //Successful processing
503  return NO_ERROR;
504 }
505 
506 
507 /**
508  * @brief Format SSH_MSG_REQUEST_SUCCESS message
509  * @param[in] connection Pointer to the SSH connection
510  * @param[out] p Buffer where to format the message
511  * @param[out] length Length of the resulting message, in bytes
512  * @return Error code
513  **/
514 
516  size_t *length)
517 {
518  //Set message type
520 
521  //Usually, the response specific data is non-existent (refer to RFC 4254,
522  //section 4)
523  *length = sizeof(uint8_t);
524 
525  //Successful processing
526  return NO_ERROR;
527 }
528 
529 
530 /**
531  * @brief Format SSH_MSG_REQUEST_FAILURE message
532  * @param[in] connection Pointer to the SSH connection
533  * @param[out] p Buffer where to format the message
534  * @param[out] length Length of the resulting message, in bytes
535  * @return Error code
536  **/
537 
539  size_t *length)
540 {
541  //Set message type
543 
544  //Total length of the message
545  *length = sizeof(uint8_t);
546 
547  //Successful processing
548  return NO_ERROR;
549 }
550 
551 
552 /**
553  * @brief Format SSH_MSG_CHANNEL_REQUEST message
554  * @param[in] channel Handle referencing an SSH channel
555  * @param[in] requestType NULL-terminated string containing the request type
556  * @param[in] requestParams Pointer to the request specific parameters
557  * @param[in] wantReply This flag specifies whether a reply is expected
558  * @param[out] p Buffer where to format the message
559  * @param[out] length Length of the resulting message, in bytes
560  * @return Error code
561  **/
562 
563 error_t sshFormatChannelRequest(SshChannel *channel, const char_t *requestType,
564  const void *requestParams, bool_t wantReply, uint8_t *p, size_t *length)
565 {
566  error_t error;
567  size_t n;
568 
569  //Total length of the message
570  *length = 0;
571 
572  //Set message type
574 
575  //Point to the first field of the message
576  p += sizeof(uint8_t);
577  *length += sizeof(uint8_t);
578 
579  //Set recipient channel number
580  STORE32BE(channel->remoteChannelNum, p);
581 
582  //Point to the next field
583  p += sizeof(uint32_t);
584  *length += sizeof(uint32_t);
585 
586  //Set request type
587  error = sshFormatString(requestType, p, &n);
588  //Any error to report?
589  if(error)
590  return error;
591 
592  //Point to the next field
593  p += n;
594  *length += n;
595 
596  //Set want_reply boolean
597  p[0] = wantReply ? TRUE : FALSE;
598 
599  //Point to the next field
600  p += sizeof(uint8_t);
601  *length += sizeof(uint8_t);
602 
603  //Check request type
604  if(!osStrcmp(requestType, "pty-req"))
605  {
606  //Format "pty-req" request specific data
607  error = sshFormatPtyReqParams(requestParams, p, &n);
608  }
609  else if(!osStrcmp(requestType, "shell"))
610  {
611  //The "shell" request does not contain type-specific data
612  n = 0;
613  }
614  else if(!osStrcmp(requestType, "exec"))
615  {
616  //Format "exec" request specific data
617  error = sshFormatExecParams(requestParams, p, &n);
618  }
619  else if(!osStrcmp(requestType, "subsystem"))
620  {
621  //Format "subsystem" request specific data
622  error = sshFormatSubsystemParams(requestParams, p, &n);
623  }
624  else if(!osStrcmp(requestType, "window-change"))
625  {
626  //Format "window-change" request specific data
627  error = sshFormatWindowChangeParams(requestParams, p, &n);
628  }
629  else if(!osStrcmp(requestType, "signal"))
630  {
631  //Format "signal" request specific data
632  error = sshFormatSignalParams(requestParams, p, &n);
633  }
634  else if(!osStrcmp(requestType, "exit-status"))
635  {
636  //Format "exit-status" request specific data
637  error = sshFormatExitStatusParams(requestParams, p, &n);
638  }
639  else if(!osStrcmp(requestType, "break"))
640  {
641  //Format "break" request specific data
642  error = sshFormatBreakParams(requestParams, p, &n);
643  }
644  else
645  {
646  //Report an error
648  }
649 
650  //Check status code
651  if(!error)
652  {
653  //Total length of the message
654  *length += n;
655  }
656 
657  //Return status code
658  return error;
659 }
660 
661 
662 /**
663  * @brief Format "pty-req" channel request parameters
664  * @param[in] params Pointer to the request specific parameters
665  * @param[out] p Output stream where to write the request specific data
666  * @param[out] written Total number of bytes that have been written
667  * @return Error code
668  **/
669 
671  uint8_t *p, size_t *written)
672 {
673  error_t error;
674  size_t n;
675 
676  //Check parameters
677  if(params == NULL)
679 
680  //Total length of the request specific data
681  *written = 0;
682 
683  //Set terminal environment variables
684  error = sshFormatBinaryString(params->termEnvVar.value,
685  params->termEnvVar.length, p, &n);
686  //Any error to report?
687  if(error)
688  return error;
689 
690  //Point to the next field
691  p += n;
692  *written += n;
693 
694  //Set terminal width (in characters)
695  STORE32BE(params->termWidthChars, p);
696 
697  //Point to the next field
698  p += sizeof(uint32_t);
699  *written += sizeof(uint32_t);
700 
701  //Set terminal height (in rows)
702  STORE32BE(params->termHeightRows, p);
703 
704  //Point to the next field
705  p += sizeof(uint32_t);
706  *written += sizeof(uint32_t);
707 
708  //Set terminal width (in pixels)
709  STORE32BE(params->termWidthPixels, p);
710 
711  //Point to the next field
712  p += sizeof(uint32_t);
713  *written += sizeof(uint32_t);
714 
715  //Set terminal height (in pixels)
716  STORE32BE(params->termHeightPixels, p);
717 
718  //Point to the next field
719  p += sizeof(uint32_t);
720  *written += sizeof(uint32_t);
721 
722  //Set terminal environment variables
723  error = sshFormatBinaryString(params->termModes.value,
724  params->termModes.length, p, &n);
725  //Any error to report?
726  if(error)
727  return error;
728 
729  //Total number of bytes that have been written
730  *written += n;
731 
732  //Successful processing
733  return NO_ERROR;
734 }
735 
736 
737 /**
738  * @brief Format "exec" channel request parameters
739  * @param[in] params Pointer to the request specific parameters
740  * @param[out] p Output stream where to write the request specific data
741  * @param[out] written Total number of bytes that have been written
742  * @return Error code
743  **/
744 
746  uint8_t *p, size_t *written)
747 {
748  error_t error;
749 
750  //Check parameters
751  if(params == NULL)
753 
754  //Set command line
755  error = sshFormatBinaryString(params->command.value,
756  params->command.length, p, written);
757 
758  //Return status code
759  return error;
760 }
761 
762 
763 /**
764  * @brief Format "subsystem" channel request parameters
765  * @param[in] params Pointer to the request specific parameters
766  * @param[out] p Output stream where to write the request specific data
767  * @param[out] written Total number of bytes that have been written
768  * @return Error code
769  **/
770 
772  uint8_t *p, size_t *written)
773 {
774  error_t error;
775 
776  //Check parameters
777  if(params == NULL)
779 
780  //Set subsystem name
781  error = sshFormatBinaryString(params->subsystemName.value,
782  params->subsystemName.length, p, written);
783 
784  //Return status code
785  return error;
786 }
787 
788 
789 /**
790  * @brief Format "window-change" channel request parameters
791  * @param[in] params Pointer to the request specific parameters
792  * @param[out] p Output stream where to write the request specific data
793  * @param[out] written Total number of bytes that have been written
794  * @return Error code
795  **/
796 
798  uint8_t *p, size_t *written)
799 {
800  //Check parameters
801  if(params == NULL)
803 
804  //Total length of the request specific data
805  *written = 0;
806 
807  //Set terminal width (in characters)
808  STORE32BE(params->termWidthChars, p);
809 
810  //Point to the next field
811  p += sizeof(uint32_t);
812  *written += sizeof(uint32_t);
813 
814  //Set terminal height (in rows)
815  STORE32BE(params->termHeightRows, p);
816 
817  //Point to the next field
818  p += sizeof(uint32_t);
819  *written += sizeof(uint32_t);
820 
821  //Set terminal width (in pixels)
822  STORE32BE(params->termWidthPixels, p);
823 
824  //Point to the next field
825  p += sizeof(uint32_t);
826  *written += sizeof(uint32_t);
827 
828  //Set terminal height (in pixels)
829  STORE32BE(params->termHeightPixels, p);
830 
831  //Total number of bytes that have been written
832  *written += sizeof(uint32_t);
833 
834  //Successful processing
835  return NO_ERROR;
836 }
837 
838 
839 /**
840  * @brief Format "signal" channel request parameters
841  * @param[in] params Pointer to the request specific parameters
842  * @param[out] p Output stream where to write the request specific data
843  * @param[out] written Total number of bytes that have been written
844  * @return Error code
845  **/
846 
848  uint8_t *p, size_t *written)
849 {
850  error_t error;
851 
852  //Check parameters
853  if(params == NULL)
855 
856  //Set signal name
857  error = sshFormatBinaryString(params->signalName.value,
858  params->signalName.length, p, written);
859 
860  //Return status code
861  return error;
862 }
863 
864 
865 /**
866  * @brief Format "exit-status" channel request parameters
867  * @param[in] params Pointer to the request specific parameters
868  * @param[out] p Output stream where to write the request specific data
869  * @param[out] written Total number of bytes that have been written
870  * @return Error code
871  **/
872 
874  uint8_t *p, size_t *written)
875 {
876  //Check parameters
877  if(params == NULL)
879 
880  //Set exit status
881  STORE32BE(params->exitStatus, p);
882 
883  //Total number of bytes that have been written
884  *written = sizeof(uint32_t);
885 
886  //Successful processing
887  return NO_ERROR;
888 }
889 
890 
891 /**
892  * @brief Format "break" channel request parameters
893  * @param[in] params Pointer to the request specific parameters
894  * @param[out] p Output stream where to write the request specific data
895  * @param[out] written Total number of bytes that have been written
896  * @return Error code
897  **/
898 
900  uint8_t *p, size_t *written)
901 {
902  //Check parameters
903  if(params == NULL)
905 
906  //Set break length (in milliseconds)
907  STORE32BE(params->breakLen, p);
908 
909  //Total number of bytes that have been written
910  *written = sizeof(uint32_t);
911 
912  //Successful processing
913  return NO_ERROR;
914 }
915 
916 
917 /**
918  * @brief Format SSH_MSG_CHANNEL_SUCCESS message
919  * @param[in] channel Handle referencing an SSH channel
920  * @param[out] p Buffer where to format the message
921  * @param[out] length Length of the resulting message, in bytes
922  * @return Error code
923  **/
924 
926  size_t *length)
927 {
928  //Total length of the message
929  *length = 0;
930 
931  //Set message type
933 
934  //Point to the first field of the message
935  p += sizeof(uint8_t);
936  *length += sizeof(uint8_t);
937 
938  //Set recipient channel
939  STORE32BE(channel->remoteChannelNum, p);
940 
941  //Total length of the message
942  *length += sizeof(uint32_t);
943 
944  //Successful processing
945  return NO_ERROR;
946 }
947 
948 
949 /**
950  * @brief Format SSH_MSG_CHANNEL_FAILURE message
951  * @param[in] channel Handle referencing an SSH channel
952  * @param[out] p Buffer where to format the message
953  * @param[out] length Length of the resulting message, in bytes
954  * @return Error code
955  **/
956 
958  size_t *length)
959 {
960  //Total length of the message
961  *length = 0;
962 
963  //Set message type
965 
966  //Point to the first field of the message
967  p += sizeof(uint8_t);
968  *length += sizeof(uint8_t);
969 
970  //Set recipient channel
971  STORE32BE(channel->remoteChannelNum, p);
972 
973  //Total length of the message
974  *length += sizeof(uint32_t);
975 
976  //Successful processing
977  return NO_ERROR;
978 }
979 
980 
981 /**
982  * @brief Parse SSH_MSG_GLOBAL_REQUEST message
983  * @param[in] connection Pointer to the SSH connection
984  * @param[in] message Pointer to message
985  * @param[in] length Length of the message, in bytes
986  * @return Error code
987  **/
988 
990  const uint8_t *message, size_t length)
991 {
992  error_t error;
993  uint_t i;
994  const uint8_t *p;
995  SshString requestName;
996  SshBoolean wantReply;
997  SshContext *context;
998 
999  //Point to the SSH context
1000  context = connection->context;
1001 
1002  //Debug message
1003  TRACE_INFO("SSH_MSG_GLOBAL_REQUEST message received (%" PRIuSIZE " bytes)...\r\n", length);
1005 
1006  //Check connection state
1007  if(connection->state != SSH_CONN_STATE_OPEN)
1008  return ERROR_UNEXPECTED_MESSAGE;
1009 
1010  //Sanity check
1011  if(length < sizeof(uint8_t))
1012  return ERROR_INVALID_MESSAGE;
1013 
1014  //Point to the first field of the message
1015  p = message + sizeof(uint8_t);
1016  //Remaining bytes to process
1017  length -= sizeof(uint8_t);
1018 
1019  //Decode the request name
1020  error = sshParseString(p, length, &requestName);
1021  //Any error to report?
1022  if(error)
1023  return error;
1024 
1025  //Point to the next field
1026  p += sizeof(uint32_t) + requestName.length;
1027  length -= sizeof(uint32_t) + requestName.length;
1028 
1029  //Malformed message?
1030  if(length < sizeof(uint8_t))
1031  return ERROR_INVALID_MESSAGE;
1032 
1033  //Decode want_reply field
1034  wantReply = p[0];
1035 
1036  //Point to the next field
1037  p += sizeof(uint8_t);
1038  length -= sizeof(uint8_t);
1039 
1040  //Initialize status code
1041  error = ERROR_UNKNOWN_REQUEST;
1042 
1043  //Acquire exclusive access to the SSH context
1044  osAcquireMutex(&context->mutex);
1045 
1046  //Multiple callbacks may be registered
1047  for(i = 0; i < SSH_MAX_GLOBAL_REQ_CALLBACKS &&
1048  error == ERROR_UNKNOWN_REQUEST; i++)
1049  {
1050  //Valid callback function?
1051  if(context->globalReqCallback[i] != NULL)
1052  {
1053  //Process global request
1054  error = context->globalReqCallback[i](connection, &requestName, p,
1055  length, context->globalReqParam[i]);
1056  }
1057  }
1058 
1059  //Release exclusive access to the SSH context
1060  osReleaseMutex(&context->mutex);
1061 
1062  //Check the value of the want_reply boolean
1063  if(!wantReply)
1064  {
1065  //If want_reply is FALSE, no response will be sent to the request
1066  error = NO_ERROR;
1067  }
1068  else
1069  {
1070  //Otherwise, the recipient responds with either SSH_MSG_REQUEST_SUCCESS
1071  //or SSH_MSG_REQUEST_FAILURE
1072  if(!error)
1073  {
1074  //Send an SSH_MSG_REQUEST_SUCCESS response
1075  error = sshSendRequestSuccess(connection);
1076  }
1077  else
1078  {
1079  //If the recipient does not recognize or support the request, it simply
1080  //responds with SSH_MSG_REQUEST_FAILURE (refer to RFC 4254, section 4)
1081  error = sshSendRequestFailure(connection);
1082  }
1083  }
1084 
1085  //Return status code
1086  return error;
1087 }
1088 
1089 
1090 /**
1091  * @brief Parse "tcpip-forward" global request parameters
1092  * @param[in] p Pointer to the request specific data
1093  * @param[in] length Length of the request specific data, in bytes
1094  * @param[out] params Information resulting from the parsing process
1095  * @return Error code
1096  **/
1097 
1098 error_t sshParseTcpIpFwdParams(const uint8_t *p, size_t length,
1099  SshTcpIpFwdParams *params)
1100 {
1101  error_t error;
1102 
1103  //The 'address to bind' field specifies the IP address on which connections
1104  //for forwarding are to be accepted
1105  error = sshParseString(p, length, &params->addrToBind);
1106  //Any error to report?
1107  if(error)
1108  return error;
1109 
1110  //Point to the next field
1111  p += sizeof(uint32_t) + params->addrToBind.length;
1112  length -= sizeof(uint32_t) + params->addrToBind.length;
1113 
1114  //Malformed message?
1115  if(length != sizeof(uint32_t))
1116  return ERROR_INVALID_MESSAGE;
1117 
1118  //The 'port number to bind' field specifies the port on which connections
1119  //for forwarding are to be accepted
1120  params->portNumToBind = LOAD32BE(p);
1121 
1122  //Invalid port number?
1123  if(params->portNumToBind > SSH_MAX_PORT_NUM)
1124  return ERROR_INVALID_PORT;
1125 
1126  //Debug message
1127  TRACE_INFO(" Address To Bind = %s\r\n", params->addrToBind.value);
1128  TRACE_INFO(" Port Number To Bind = %" PRIu32 "\r\n", params->portNumToBind);
1129 
1130  //Successful processing
1131  return NO_ERROR;
1132 }
1133 
1134 
1135 /**
1136  * @brief Parse "cancel-tcpip-forward" global request parameters
1137  * @param[in] p Pointer to the request specific data
1138  * @param[in] length Length of the request specific data, in bytes
1139  * @param[out] params Information resulting from the parsing process
1140  * @return Error code
1141  **/
1142 
1144  SshCancelTcpIpFwdParams *params)
1145 {
1146  error_t error;
1147 
1148  //Parse 'address to bind' field
1149  error = sshParseString(p, length, &params->addrToBind);
1150  //Any error to report?
1151  if(error)
1152  return error;
1153 
1154  //Point to the next field
1155  p += sizeof(uint32_t) + params->addrToBind.length;
1156  length -= sizeof(uint32_t) + params->addrToBind.length;
1157 
1158  //Malformed message?
1159  if(length != sizeof(uint32_t))
1160  return ERROR_INVALID_MESSAGE;
1161 
1162  //Parse 'port number to bind' field
1163  params->portNumToBind = LOAD32BE(p);
1164 
1165  //Invalid port number?
1166  if(params->portNumToBind > SSH_MAX_PORT_NUM)
1167  return ERROR_INVALID_PORT;
1168 
1169  //Debug message
1170  TRACE_INFO(" Address To Bind = %s\r\n", params->addrToBind.value);
1171  TRACE_INFO(" Port Number To Bind = %" PRIu32 "\r\n", params->portNumToBind);
1172 
1173  //Successful processing
1174  return NO_ERROR;
1175 }
1176 
1177 
1178 /**
1179  * @brief Parse "elevation" global request parameters
1180  * @param[in] p Pointer to the request specific data
1181  * @param[in] length Length of the request specific data, in bytes
1182  * @param[out] params Information resulting from the parsing process
1183  * @return Error code
1184  **/
1185 
1186 error_t sshParseElevationParams(const uint8_t *p, size_t length,
1187  SshElevationParams *params)
1188 {
1189  //Malformed message?
1190  if(length != sizeof(uint8_t))
1191  return ERROR_INVALID_MESSAGE;
1192 
1193  //The server use the 'elevation performed' field to indicates to the client
1194  //whether elevation was done
1195  params->elevationPerformed = p[0];
1196 
1197  //Successful processing
1198  return NO_ERROR;
1199 }
1200 
1201 
1202 /**
1203  * @brief Parse SSH_MSG_REQUEST_SUCCESS message
1204  * @param[in] connection Pointer to the SSH connection
1205  * @param[in] message Pointer to message
1206  * @param[in] length Length of the message, in bytes
1207  * @return Error code
1208  **/
1209 
1211  const uint8_t *message, size_t length)
1212 {
1213  //Debug message
1214  TRACE_INFO("SSH_MSG_REQUEST_SUCCESS message received (%" PRIuSIZE " bytes)...\r\n", length);
1216 
1217  //Check connection state
1218  if(connection->state != SSH_CONN_STATE_OPEN)
1219  return ERROR_UNEXPECTED_MESSAGE;
1220 
1221  //Sanity check
1222  if(length < sizeof(uint8_t))
1223  return ERROR_INVALID_MESSAGE;
1224 
1225  //Check global request state
1226  if(connection->requestState != SSH_REQUEST_STATE_PENDING)
1227  return ERROR_UNEXPECTED_MESSAGE;
1228 
1229  //Update global request state
1230  connection->requestState = SSH_REQUEST_STATE_SUCCESS;
1231 
1232  //Successful processing
1233  return NO_ERROR;
1234 }
1235 
1236 
1237 /**
1238  * @brief Parse SSH_MSG_REQUEST_FAILURE message
1239  * @param[in] connection Pointer to the SSH connection
1240  * @param[in] message Pointer to message
1241  * @param[in] length Length of the message, in bytes
1242  * @return Error code
1243  **/
1244 
1246  const uint8_t *message, size_t length)
1247 {
1248  //Debug message
1249  TRACE_INFO("SSH_MSG_REQUEST_FAILURE message received (%" PRIuSIZE " bytes)...\r\n", length);
1251 
1252  //Check connection state
1253  if(connection->state != SSH_CONN_STATE_OPEN)
1254  return ERROR_UNEXPECTED_MESSAGE;
1255 
1256  //Malformed message?
1257  if(length != sizeof(uint8_t))
1258  return ERROR_INVALID_MESSAGE;
1259 
1260  //Check global request state
1261  if(connection->requestState != SSH_REQUEST_STATE_PENDING)
1262  return ERROR_UNEXPECTED_MESSAGE;
1263 
1264  //Update global request state
1265  connection->requestState = SSH_REQUEST_STATE_FAILURE;
1266 
1267  //Successful processing
1268  return NO_ERROR;
1269 }
1270 
1271 
1272 /**
1273  * @brief Parse SSH_MSG_CHANNEL_REQUEST message
1274  * @param[in] connection Pointer to the SSH connection
1275  * @param[in] message Pointer to message
1276  * @param[in] length Length of the message, in bytes
1277  * @return Error code
1278  **/
1279 
1281  const uint8_t *message, size_t length)
1282 {
1283  error_t error;
1284  uint_t i;
1285  const uint8_t *p;
1286  uint32_t recipientChannel;
1287  SshString requestType;
1288  SshBoolean wantReply;
1289  SshChannel *channel;
1290  SshContext *context;
1291 
1292  //Point to the SSH context
1293  context = connection->context;
1294 
1295  //Debug message
1296  TRACE_INFO("SSH_MSG_CHANNEL_REQUEST message received (%" PRIuSIZE " bytes)...\r\n", length);
1298 
1299  //Check connection state
1300  if(connection->state != SSH_CONN_STATE_OPEN)
1301  return ERROR_UNEXPECTED_MESSAGE;
1302 
1303  //Sanity check
1304  if(length < sizeof(uint8_t))
1305  return ERROR_INVALID_MESSAGE;
1306 
1307  //Point to the first field of the message
1308  p = message + sizeof(uint8_t);
1309  //Remaining bytes to process
1310  length -= sizeof(uint8_t);
1311 
1312  //Malformed message?
1313  if(length < sizeof(uint32_t))
1314  return ERROR_INVALID_MESSAGE;
1315 
1316  //Get recipient channel number
1317  recipientChannel = LOAD32BE(p);
1318 
1319  //Point to the next field
1320  p += sizeof(uint32_t);
1321  length -= sizeof(uint32_t);
1322 
1323  //Decode the request type
1324  error = sshParseString(p, length, &requestType);
1325  //Any error to report?
1326  if(error)
1327  return error;
1328 
1329  //Point to the next field
1330  p += sizeof(uint32_t) + requestType.length;
1331  length -= sizeof(uint32_t) + requestType.length;
1332 
1333  //Malformed message?
1334  if(length < sizeof(uint8_t))
1335  return ERROR_INVALID_MESSAGE;
1336 
1337  //Decode want_reply field
1338  wantReply = p[0];
1339 
1340  //Point to the next field
1341  p += sizeof(uint8_t);
1342  length -= sizeof(uint8_t);
1343 
1344  //Acquire exclusive access to the SSH context
1345  osAcquireMutex(&context->mutex);
1346 
1347  //Point to the matching channel
1348  channel = sshGetChannel(connection, recipientChannel);
1349 
1350  //Valid channel?
1351  if(channel != NULL)
1352  {
1353  //Check channel state
1354  if(channel->state == SSH_CHANNEL_STATE_OPEN && !channel->closeReceived)
1355  {
1356  //Initialize status code
1357  error = ERROR_UNKNOWN_REQUEST;
1358 
1359  //Multiple callbacks may be registered
1360  for(i = 0; i < SSH_MAX_CHANNEL_REQ_CALLBACKS &&
1361  error == ERROR_UNKNOWN_REQUEST; i++)
1362  {
1363  //Valid callback function?
1364  if(context->channelReqCallback[i] != NULL)
1365  {
1366  //Process channel request
1367  error = context->channelReqCallback[i](channel, &requestType, p,
1368  length, context->channelReqParam[i]);
1369  }
1370  }
1371 
1372  //Check the value of the want_reply boolean
1373  if(!wantReply || channel->closeSent)
1374  {
1375  //If want_reply is FALSE, no response will be sent to the request
1376  error = NO_ERROR;
1377  }
1378  else
1379  {
1380  //Otherwise, the recipient responds with either SSH_MSG_CHANNEL_SUCCESS,
1381  //SSH_MSG_CHANNEL_FAILURE, or request-specific continuation messages
1382  if(!error)
1383  {
1384  //Send an SSH_MSG_CHANNEL_SUCCESS response
1385  error = sshSendChannelSuccess(channel);
1386  }
1387  else
1388  {
1389  //If the request is not recognized or is not supported for the
1390  //channel, SSH_MSG_CHANNEL_FAILURE is returned (refer to RFC 4254,
1391  //section 5.4)
1392  error = sshSendChannelFailure(channel);
1393  }
1394  }
1395  }
1396  else
1397  {
1398  //Invalid channel state
1399  error = ERROR_UNEXPECTED_MESSAGE;
1400  }
1401  }
1402  else
1403  {
1404  //The recipient channel number is not valid
1405  error = ERROR_INVALID_CHANNEL;
1406  }
1407 
1408  //Release exclusive access to the SSH context
1409  osReleaseMutex(&context->mutex);
1410 
1411  //Return status code
1412  return error;
1413 }
1414 
1415 
1416 /**
1417  * @brief Parse "pty-req" channel request parameters
1418  * @param[in] p Pointer to the request specific data
1419  * @param[in] length Length of the request specific data, in bytes
1420  * @param[out] params Information resulting from the parsing process
1421  * @return Error code
1422  **/
1423 
1424 error_t sshParsePtyReqParams(const uint8_t *p, size_t length,
1425  SshPtyReqParams *params)
1426 {
1427  error_t error;
1428 
1429  //Parse the terminal environment variable value
1430  error = sshParseString(p, length, &params->termEnvVar);
1431  //Any error to report?
1432  if(error)
1433  return error;
1434 
1435  //Point to the next field
1436  p += sizeof(uint32_t) + params->termEnvVar.length;
1437  length -= sizeof(uint32_t) + params->termEnvVar.length;
1438 
1439  //Malformed request?
1440  if(length < sizeof(uint32_t))
1441  return ERROR_INVALID_MESSAGE;
1442 
1443  //Get terminal width (in characters)
1444  params->termWidthChars = LOAD32BE(p);
1445 
1446  //Point to the next field
1447  p += sizeof(uint32_t);
1448  length -= sizeof(uint32_t);
1449 
1450  //Malformed request?
1451  if(length < sizeof(uint32_t))
1452  return ERROR_INVALID_MESSAGE;
1453 
1454  //Get terminal height (in rows)
1455  params->termHeightRows = LOAD32BE(p);
1456 
1457  //Point to the next field
1458  p += sizeof(uint32_t);
1459  length -= sizeof(uint32_t);
1460 
1461  //Malformed request?
1462  if(length < sizeof(uint32_t))
1463  return ERROR_INVALID_MESSAGE;
1464 
1465  //Get terminal width (in pixels)
1466  params->termWidthPixels = LOAD32BE(p);
1467 
1468  //Point to the next field
1469  p += sizeof(uint32_t);
1470  length -= sizeof(uint32_t);
1471 
1472  //Malformed request?
1473  if(length < sizeof(uint32_t))
1474  return ERROR_INVALID_MESSAGE;
1475 
1476  //Get terminal height (in pixels)
1477  params->termHeightPixels = LOAD32BE(p);
1478 
1479  //Point to the next field
1480  p += sizeof(uint32_t);
1481  length -= sizeof(uint32_t);
1482 
1483  //Parse the encoded terminal modes
1484  error = sshParseBinaryString(p, length, &params->termModes);
1485  //Any error to report?
1486  if(error)
1487  return error;
1488 
1489  //Malformed request?
1490  if(length != (sizeof(uint32_t) + params->termModes.length))
1491  return ERROR_INVALID_MESSAGE;
1492 
1493  //Debug message
1494  TRACE_INFO(" Term Width (chars) = %" PRIu32 "\r\n", params->termWidthChars);
1495  TRACE_INFO(" Term Height (rows) = %" PRIu32 "\r\n", params->termHeightRows);
1496  TRACE_INFO(" Term Width (pixels) = %" PRIu32 "\r\n", params->termWidthPixels);
1497  TRACE_INFO(" Term Height (pixels) = %" PRIu32 "\r\n", params->termHeightPixels);
1498 
1499  //Successful processing
1500  return NO_ERROR;
1501 }
1502 
1503 
1504 /**
1505  * @brief Parse "exec" channel request parameters
1506  * @param[in] p Pointer to the request specific data
1507  * @param[in] length Length of the request specific data, in bytes
1508  * @param[out] params Information resulting from the parsing process
1509  * @return Error code
1510  **/
1511 
1512 error_t sshParseExecParams(const uint8_t *p, size_t length,
1513  SshExecParams *params)
1514 {
1515  error_t error;
1516 
1517  //Parse command
1518  error = sshParseString(p, length, &params->command);
1519  //Any error to report?
1520  if(error)
1521  return error;
1522 
1523  //Malformed request?
1524  if(length != (sizeof(uint32_t) + params->command.length))
1525  return ERROR_INVALID_MESSAGE;
1526 
1527  //Successful processing
1528  return NO_ERROR;
1529 }
1530 
1531 
1532 /**
1533  * @brief Retrieve the specified argument from an "exec" request
1534  * @param[in] params Pointer to the "exec" request parameters
1535  * @param[in] index Zero-based index of the argument
1536  * @param[out] arg Value of the argument
1537  * @return TRUE if the index is valid, else FALSE
1538  **/
1539 
1541 {
1542  size_t i;
1543  size_t j;
1544  uint_t n;
1545 
1546  //Initialize variables
1547  i = 0;
1548  n = 0;
1549 
1550  //Parse the command line
1551  for(j = 0; j <= params->command.length; j++)
1552  {
1553  //Arguments are separated by whitespace characters
1554  if(j == params->command.length || osIsblank(params->command.value[j]))
1555  {
1556  //Non-empty string?
1557  if(i < j)
1558  {
1559  //Matching index?
1560  if(n++ == index)
1561  {
1562  //Point to first character of the argument
1563  arg->value = params->command.value + i;
1564  //Determine the length of the argument
1565  arg->length = j - i;
1566 
1567  //The index is valid
1568  return TRUE;
1569  }
1570  }
1571 
1572  //Point to the next argument of the list
1573  i = j + 1;
1574  }
1575  }
1576 
1577  //The index is out of range
1578  return FALSE;
1579 }
1580 
1581 
1582 /**
1583  * @brief Parse "subsystem" channel request parameters
1584  * @param[in] p Pointer to the request specific data
1585  * @param[in] length Length of the request specific data, in bytes
1586  * @param[out] params Information resulting from the parsing process
1587  * @return Error code
1588  **/
1589 
1590 error_t sshParseSubsystemParams(const uint8_t *p, size_t length,
1591  SshSubsystemParams *params)
1592 {
1593  error_t error;
1594 
1595  //Parse subsystem name
1596  error = sshParseString(p, length, &params->subsystemName);
1597  //Any error to report?
1598  if(error)
1599  return error;
1600 
1601  //Malformed request?
1602  if(length != (sizeof(uint32_t) + params->subsystemName.length))
1603  return ERROR_INVALID_MESSAGE;
1604 
1605  //Successful processing
1606  return NO_ERROR;
1607 }
1608 
1609 
1610 /**
1611  * @brief Parse "window-change" channel request parameters
1612  * @param[in] p Pointer to the request specific data
1613  * @param[in] length Length of the request specific data, in bytes
1614  * @param[out] params Information resulting from the parsing process
1615  * @return Error code
1616  **/
1617 
1619  SshWindowChangeParams *params)
1620 {
1621  //Malformed request?
1622  if(length < sizeof(uint32_t))
1623  return ERROR_INVALID_MESSAGE;
1624 
1625  //Get terminal width (in characters)
1626  params->termWidthChars = LOAD32BE(p);
1627 
1628  //Point to the next field
1629  p += sizeof(uint32_t);
1630  length -= sizeof(uint32_t);
1631 
1632  //Malformed request?
1633  if(length < sizeof(uint32_t))
1634  return ERROR_INVALID_MESSAGE;
1635 
1636  //Get terminal height (in rows)
1637  params->termHeightRows = LOAD32BE(p);
1638 
1639  //Point to the next field
1640  p += sizeof(uint32_t);
1641  length -= sizeof(uint32_t);
1642 
1643  //Malformed request?
1644  if(length < sizeof(uint32_t))
1645  return ERROR_INVALID_MESSAGE;
1646 
1647  //Get terminal width (in pixels)
1648  params->termWidthPixels = LOAD32BE(p);
1649 
1650  //Point to the next field
1651  p += sizeof(uint32_t);
1652  length -= sizeof(uint32_t);
1653 
1654  //Malformed request?
1655  if(length != sizeof(uint32_t))
1656  return ERROR_INVALID_MESSAGE;
1657 
1658  //Get terminal height (in pixels)
1659  params->termHeightPixels = LOAD32BE(p);
1660 
1661  //Debug message
1662  TRACE_INFO(" Term Width (chars) = %" PRIu32 "\r\n", params->termWidthChars);
1663  TRACE_INFO(" Term Height (rows) = %" PRIu32 "\r\n", params->termHeightRows);
1664  TRACE_INFO(" Term Width (pixels) = %" PRIu32 "\r\n", params->termWidthPixels);
1665  TRACE_INFO(" Term Height (pixels) = %" PRIu32 "\r\n", params->termHeightPixels);
1666 
1667  //Successful processing
1668  return NO_ERROR;
1669 }
1670 
1671 
1672 /**
1673  * @brief Parse "signal" channel request parameters
1674  * @param[in] p Pointer to the request specific data
1675  * @param[in] length Length of the request specific data, in bytes
1676  * @param[out] params Information resulting from the parsing process
1677  * @return Error code
1678  **/
1679 
1680 error_t sshParseSignalParams(const uint8_t *p, size_t length,
1681  SshSignalParams *params)
1682 {
1683  error_t error;
1684 
1685  //Parse signal name
1686  error = sshParseString(p, length, &params->signalName);
1687  //Any error to report?
1688  if(error)
1689  return error;
1690 
1691  //Malformed request?
1692  if(length != (sizeof(uint32_t) + params->signalName.length))
1693  return ERROR_INVALID_MESSAGE;
1694 
1695  //Successful processing
1696  return NO_ERROR;
1697 }
1698 
1699 
1700 /**
1701  * @brief Parse "exit-status" channel request parameters
1702  * @param[in] p Pointer to the request specific data
1703  * @param[in] length Length of the request specific data, in bytes
1704  * @param[out] params Information resulting from the parsing process
1705  * @return Error code
1706  **/
1707 
1708 error_t sshParseExitStatusParams(const uint8_t *p, size_t length,
1709  SshExitStatusParams *params)
1710 {
1711  //Malformed request?
1712  if(length != sizeof(uint32_t))
1713  return ERROR_INVALID_MESSAGE;
1714 
1715  //Get exit status
1716  params->exitStatus = LOAD32BE(p);
1717 
1718  //Debug message
1719  TRACE_INFO(" Exit status = %" PRIu32 "\r\n", params->exitStatus);
1720 
1721  //Successful processing
1722  return NO_ERROR;
1723 }
1724 
1725 /**
1726  * @brief Parse "break" channel request parameters
1727  * @param[in] p Pointer to the request specific data
1728  * @param[in] length Length of the request specific data, in bytes
1729  * @param[out] params Information resulting from the parsing process
1730  * @return Error code
1731  **/
1732 
1733 error_t sshParseBreakParams(const uint8_t *p, size_t length,
1734  SshBreakParams *params)
1735 {
1736  //Malformed request?
1737  if(length != sizeof(uint32_t))
1738  return ERROR_INVALID_MESSAGE;
1739 
1740  //Get break length (in milliseconds)
1741  params->breakLen = LOAD32BE(p);
1742 
1743  //Debug message
1744  TRACE_INFO(" Break Length (ms) = %" PRIu32 "\r\n", params->breakLen);
1745 
1746  //Successful processing
1747  return NO_ERROR;
1748 }
1749 
1750 
1751 /**
1752  * @brief Parse SSH_MSG_CHANNEL_SUCCESS message
1753  * @param[in] connection Pointer to the SSH connection
1754  * @param[in] message Pointer to message
1755  * @param[in] length Length of the message, in bytes
1756  * @return Error code
1757  **/
1758 
1760  const uint8_t *message, size_t length)
1761 {
1762  error_t error;
1763  const uint8_t *p;
1764  uint32_t recipientChannel;
1765  SshChannel *channel;
1766 
1767  //Debug message
1768  TRACE_INFO("SSH_MSG_CHANNEL_SUCCESS message received (%" PRIuSIZE " bytes)...\r\n", length);
1770 
1771  //Check connection state
1772  if(connection->state != SSH_CONN_STATE_OPEN)
1773  return ERROR_UNEXPECTED_MESSAGE;
1774 
1775  //Sanity check
1776  if(length < sizeof(uint8_t))
1777  return ERROR_INVALID_MESSAGE;
1778 
1779  //Point to the first field of the message
1780  p = message + sizeof(uint8_t);
1781  //Remaining bytes to process
1782  length -= sizeof(uint8_t);
1783 
1784  //Malformed message?
1785  if(length != sizeof(uint32_t))
1786  return ERROR_INVALID_MESSAGE;
1787 
1788  //Decode the recipient channel
1789  recipientChannel = LOAD32BE(p);
1790 
1791  //Debug message
1792  TRACE_INFO(" Recipient Channel = %" PRIu32 "\r\n", recipientChannel);
1793 
1794  //Acquire exclusive access to the SSH context
1795  osAcquireMutex(&connection->context->mutex);
1796 
1797  //Point to the matching channel
1798  channel = sshGetChannel(connection, recipientChannel);
1799 
1800  //Valid channel?
1801  if(channel != NULL)
1802  {
1803  //Check channel state
1804  if(channel->state == SSH_CHANNEL_STATE_OPEN && !channel->closeReceived)
1805  {
1806  //Check channel request state
1807  if(channel->requestState == SSH_REQUEST_STATE_PENDING)
1808  {
1809  //Update channel request state
1810  channel->requestState = SSH_REQUEST_STATE_SUCCESS;
1811 
1812  //Successfull processing
1813  error = NO_ERROR;
1814  }
1815  else
1816  {
1817  //Invalid channel request state
1818  error = ERROR_UNEXPECTED_MESSAGE;
1819  }
1820  }
1821  else
1822  {
1823  //Invalid channel state
1824  error = ERROR_UNEXPECTED_MESSAGE;
1825  }
1826  }
1827  else
1828  {
1829  //The recipient channel number is not valid
1830  error = ERROR_INVALID_CHANNEL;
1831  }
1832 
1833  //Release exclusive access to the SSH context
1834  osReleaseMutex(&connection->context->mutex);
1835 
1836  //Return status code
1837  return error;
1838 }
1839 
1840 
1841 /**
1842  * @brief Parse SSH_MSG_CHANNEL_FAILURE message
1843  * @param[in] connection Pointer to the SSH connection
1844  * @param[in] message Pointer to message
1845  * @param[in] length Length of the message, in bytes
1846  * @return Error code
1847  **/
1848 
1850  const uint8_t *message, size_t length)
1851 {
1852  error_t error;
1853  const uint8_t *p;
1854  uint32_t recipientChannel;
1855  SshChannel *channel;
1856 
1857  //Debug message
1858  TRACE_INFO("SSH_MSG_CHANNEL_FAILURE message received (%" PRIuSIZE " bytes)...\r\n", length);
1860 
1861  //Check connection state
1862  if(connection->state != SSH_CONN_STATE_OPEN)
1863  return ERROR_UNEXPECTED_MESSAGE;
1864 
1865  //Sanity check
1866  if(length < sizeof(uint8_t))
1867  return ERROR_INVALID_MESSAGE;
1868 
1869  //Point to the first field of the message
1870  p = message + sizeof(uint8_t);
1871  //Remaining bytes to process
1872  length -= sizeof(uint8_t);
1873 
1874  //Malformed message?
1875  if(length != sizeof(uint32_t))
1876  return ERROR_INVALID_MESSAGE;
1877 
1878  //Decode the recipient channel
1879  recipientChannel = LOAD32BE(p);
1880 
1881  //Debug message
1882  TRACE_INFO(" Recipient Channel = %" PRIu32 "\r\n", recipientChannel);
1883 
1884  //Acquire exclusive access to the SSH context
1885  osAcquireMutex(&connection->context->mutex);
1886 
1887  //Point to the matching channel
1888  channel = sshGetChannel(connection, recipientChannel);
1889 
1890  //Valid channel?
1891  if(channel != NULL)
1892  {
1893  //Check channel state
1894  if(channel->state == SSH_CHANNEL_STATE_OPEN && !channel->closeReceived)
1895  {
1896  //Check channel request state
1897  if(channel->requestState == SSH_REQUEST_STATE_PENDING)
1898  {
1899  //Update channel request state
1900  channel->requestState = SSH_REQUEST_STATE_FAILURE;
1901 
1902  //Successfull processing
1903  error = NO_ERROR;
1904  }
1905  else
1906  {
1907  //Invalid channel request state
1908  error = ERROR_UNEXPECTED_MESSAGE;
1909  }
1910  }
1911  else
1912  {
1913  //Invalid channel state
1914  error = ERROR_UNEXPECTED_MESSAGE;
1915  }
1916  }
1917  else
1918  {
1919  //The recipient channel number is not valid
1920  error = ERROR_INVALID_CHANNEL;
1921  }
1922 
1923  //Release exclusive access to the SSH context
1924  osReleaseMutex(&connection->context->mutex);
1925 
1926  //Return status code
1927  return error;
1928 }
1929 
1930 #endif
uint8_t message[]
Definition: chap.h:154
unsigned int uint_t
Definition: compiler_port.h:50
#define PRIuSIZE
char char_t
Definition: compiler_port.h:48
int bool_t
Definition: compiler_port.h:53
#define LOAD32BE(p)
Definition: cpu_endian.h:210
#define STORE32BE(a, p)
Definition: cpu_endian.h:286
Debugging facilities.
#define TRACE_INFO(...)
Definition: debug.h:95
#define TRACE_VERBOSE_ARRAY(p, a, n)
Definition: debug.h:125
uint8_t n
error_t
Error codes.
Definition: error.h:43
@ ERROR_UNSUPPORTED_REQUEST
Unsupported request.
Definition: error.h:56
@ ERROR_INVALID_PORT
Definition: error.h:104
@ ERROR_INVALID_MESSAGE
Definition: error.h:105
@ ERROR_UNKNOWN_REQUEST
Definition: error.h:276
@ NO_ERROR
Success.
Definition: error.h:44
@ ERROR_INVALID_CHANNEL
Definition: error.h:273
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
@ ERROR_UNEXPECTED_MESSAGE
Definition: error.h:194
uint8_t p
Definition: ndp.h:300
#define osStrcmp(s1, s2)
Definition: os_port.h:171
#define osIsblank(c)
Definition: os_port.h:290
#define TRUE
Definition: os_port.h:50
#define FALSE
Definition: os_port.h:46
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
Secure Shell (SSH)
#define SSH_MAX_CHANNEL_REQ_CALLBACKS
Definition: ssh.h:199
@ SSH_CHANNEL_STATE_OPEN
Definition: ssh.h:1084
@ SSH_CONN_STATE_OPEN
Definition: ssh.h:1071
#define SshChannel
Definition: ssh.h:887
#define SSH_MAX_GLOBAL_REQ_CALLBACKS
Definition: ssh.h:192
#define SshConnection
Definition: ssh.h:883
#define SshContext
Definition: ssh.h:879
@ SSH_REQUEST_STATE_IDLE
Definition: ssh.h:1095
@ SSH_REQUEST_STATE_PENDING
Definition: ssh.h:1096
@ SSH_REQUEST_STATE_SUCCESS
Definition: ssh.h:1097
@ SSH_REQUEST_STATE_FAILURE
Definition: ssh.h:1098
@ SSH_MSG_REQUEST_FAILURE
Definition: ssh.h:982
@ SSH_MSG_GLOBAL_REQUEST
Definition: ssh.h:980
@ SSH_MSG_REQUEST_SUCCESS
Definition: ssh.h:981
@ SSH_MSG_CHANNEL_FAILURE
Definition: ssh.h:993
@ SSH_MSG_CHANNEL_REQUEST
Definition: ssh.h:991
@ SSH_MSG_CHANNEL_SUCCESS
Definition: ssh.h:992
SshChannel * sshGetChannel(SshConnection *connection, uint32_t localChannelNum)
Get the channel that matches the specified channel number.
Definition: ssh_channel.c:53
SSH channel management.
error_t sshFormatString(const char_t *value, uint8_t *p, size_t *written)
Format a string.
Definition: ssh_misc.c:1384
error_t sshParseBinaryString(const uint8_t *p, size_t length, SshBinaryString *string)
Parse a binary string.
Definition: ssh_misc.c:1189
error_t sshFormatBinaryString(const void *value, size_t valueLen, uint8_t *p, size_t *written)
Format a binary string.
Definition: ssh_misc.c:1415
error_t sshParseString(const uint8_t *p, size_t length, SshString *string)
Parse a string.
Definition: ssh_misc.c:1152
SSH helper functions.
#define SSH_MAX_PORT_NUM
Definition: ssh_misc.h:39
error_t sshSendPacket(SshConnection *connection, uint8_t *payload, size_t payloadLen)
Send SSH packet.
Definition: ssh_packet.c:57
SSH packet encryption/decryption.
#define SSH_PACKET_HEADER_SIZE
Definition: ssh_packet.h:38
error_t sshFormatSubsystemParams(const SshSubsystemParams *params, uint8_t *p, size_t *written)
Format "subsystem" channel request parameters.
Definition: ssh_request.c:771
error_t sshFormatExitStatusParams(const SshExitStatusParams *params, uint8_t *p, size_t *written)
Format "exit-status" channel request parameters.
Definition: ssh_request.c:873
error_t sshSendChannelRequest(SshChannel *channel, const char_t *requestType, const void *requestParams, bool_t wantReply)
Send SSH_MSG_CHANNEL_REQUEST message.
Definition: ssh_request.c:179
error_t sshParseExitStatusParams(const uint8_t *p, size_t length, SshExitStatusParams *params)
Parse "exit-status" channel request parameters.
Definition: ssh_request.c:1708
error_t sshParseChannelRequest(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_CHANNEL_REQUEST message.
Definition: ssh_request.c:1280
error_t sshSendRequestFailure(SshConnection *connection)
Send SSH_MSG_REQUEST_FAILURE message.
Definition: ssh_request.c:142
error_t sshFormatBreakParams(const SshBreakParams *params, uint8_t *p, size_t *written)
Format "break" channel request parameters.
Definition: ssh_request.c:899
error_t sshFormatGlobalRequest(SshConnection *connection, const char_t *requestName, const void *requestParams, bool_t wantReply, uint8_t *p, size_t *length)
Format SSH_MSG_GLOBAL_REQUEST message.
Definition: ssh_request.c:324
error_t sshFormatChannelFailure(SshChannel *channel, uint8_t *p, size_t *length)
Format SSH_MSG_CHANNEL_FAILURE message.
Definition: ssh_request.c:957
error_t sshParseSignalParams(const uint8_t *p, size_t length, SshSignalParams *params)
Parse "signal" channel request parameters.
Definition: ssh_request.c:1680
error_t sshSendRequestSuccess(SshConnection *connection)
Send SSH_MSG_REQUEST_SUCCESS message.
Definition: ssh_request.c:108
bool_t sshGetExecArg(const SshExecParams *params, uint_t index, SshString *arg)
Retrieve the specified argument from an "exec" request.
Definition: ssh_request.c:1540
error_t sshFormatPtyReqParams(const SshPtyReqParams *params, uint8_t *p, size_t *written)
Format "pty-req" channel request parameters.
Definition: ssh_request.c:670
error_t sshParseSubsystemParams(const uint8_t *p, size_t length, SshSubsystemParams *params)
Parse "subsystem" channel request parameters.
Definition: ssh_request.c:1590
error_t sshParseBreakParams(const uint8_t *p, size_t length, SshBreakParams *params)
Parse "break" channel request parameters.
Definition: ssh_request.c:1733
error_t sshFormatChannelSuccess(SshChannel *channel, uint8_t *p, size_t *length)
Format SSH_MSG_CHANNEL_SUCCESS message.
Definition: ssh_request.c:925
error_t sshParseRequestSuccess(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_REQUEST_SUCCESS message.
Definition: ssh_request.c:1210
error_t sshParseCancelTcpIpFwdParams(const uint8_t *p, size_t length, SshCancelTcpIpFwdParams *params)
Parse "cancel-tcpip-forward" global request parameters.
Definition: ssh_request.c:1143
error_t sshFormatRequestSuccess(SshConnection *connection, uint8_t *p, size_t *length)
Format SSH_MSG_REQUEST_SUCCESS message.
Definition: ssh_request.c:515
error_t sshParseGlobalRequest(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_GLOBAL_REQUEST message.
Definition: ssh_request.c:989
error_t sshFormatTcpIpFwdParams(const SshTcpIpFwdParams *params, uint8_t *p, size_t *written)
Format "tcpip-forward" global request parameters.
Definition: ssh_request.c:400
error_t sshParseChannelSuccess(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_CHANNEL_SUCCESS message.
Definition: ssh_request.c:1759
error_t sshFormatRequestFailure(SshConnection *connection, uint8_t *p, size_t *length)
Format SSH_MSG_REQUEST_FAILURE message.
Definition: ssh_request.c:538
error_t sshSendChannelFailure(SshChannel *channel)
Send SSH_MSG_CHANNEL_FAILURE message.
Definition: ssh_request.c:281
error_t sshFormatElevationParams(const SshElevationParams *params, uint8_t *p, size_t *written)
Format "elevation" global request parameters.
Definition: ssh_request.c:488
error_t sshSendChannelSuccess(SshChannel *channel)
Send SSH_MSG_CHANNEL_SUCCESS message.
Definition: ssh_request.c:236
error_t sshParseWindowChangeParams(const uint8_t *p, size_t length, SshWindowChangeParams *params)
Parse "window-change" channel request parameters.
Definition: ssh_request.c:1618
error_t sshParseExecParams(const uint8_t *p, size_t length, SshExecParams *params)
Parse "exec" channel request parameters.
Definition: ssh_request.c:1512
error_t sshFormatWindowChangeParams(const SshWindowChangeParams *params, uint8_t *p, size_t *written)
Format "window-change" channel request parameters.
Definition: ssh_request.c:797
error_t sshFormatChannelRequest(SshChannel *channel, const char_t *requestType, const void *requestParams, bool_t wantReply, uint8_t *p, size_t *length)
Format SSH_MSG_CHANNEL_REQUEST message.
Definition: ssh_request.c:563
error_t sshFormatSignalParams(const SshSignalParams *params, uint8_t *p, size_t *written)
Format "signal" channel request parameters.
Definition: ssh_request.c:847
error_t sshSendGlobalRequest(SshConnection *connection, const char_t *requestName, const void *requestParams, bool_t wantReply)
Send SSH_MSG_GLOBAL_REQUEST message.
Definition: ssh_request.c:55
error_t sshFormatCancelTcpIpFwdParams(const SshCancelTcpIpFwdParams *params, uint8_t *p, size_t *written)
Format "cancel-tcpip-forward" global request parameters.
Definition: ssh_request.c:445
error_t sshParseElevationParams(const uint8_t *p, size_t length, SshElevationParams *params)
Parse "elevation" global request parameters.
Definition: ssh_request.c:1186
error_t sshParseTcpIpFwdParams(const uint8_t *p, size_t length, SshTcpIpFwdParams *params)
Parse "tcpip-forward" global request parameters.
Definition: ssh_request.c:1098
error_t sshParseChannelFailure(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_CHANNEL_FAILURE message.
Definition: ssh_request.c:1849
error_t sshFormatExecParams(const SshExecParams *params, uint8_t *p, size_t *written)
Format "exec" channel request parameters.
Definition: ssh_request.c:745
error_t sshParseRequestFailure(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_REQUEST_FAILURE message.
Definition: ssh_request.c:1245
error_t sshParsePtyReqParams(const uint8_t *p, size_t length, SshPtyReqParams *params)
Parse "pty-req" channel request parameters.
Definition: ssh_request.c:1424
Global request and channel request handling.
bool_t SshBoolean
Boolean.
Definition: ssh_types.h:48
const uint8_t * value
Definition: ssh_types.h:68
size_t length
Definition: ssh_types.h:69
"break" channel request parameters
Definition: ssh_request.h:195
uint32_t breakLen
Definition: ssh_request.h:196
"cancel-tcpip-forward" global request parameters
Definition: ssh_request.h:59
"elevation" global request parameters
Definition: ssh_request.h:70
bool_t elevationPerformed
Definition: ssh_request.h:71
"exec" channel request parameters
Definition: ssh_request.h:119
SshString command
Definition: ssh_request.h:120
"exit-status" channel request parameters
Definition: ssh_request.h:172
"pty-req" channel request parameters
Definition: ssh_request.h:80
SshString termEnvVar
Definition: ssh_request.h:81
uint32_t termWidthPixels
Definition: ssh_request.h:84
SshBinaryString termModes
Definition: ssh_request.h:86
uint32_t termHeightPixels
Definition: ssh_request.h:85
uint32_t termWidthChars
Definition: ssh_request.h:82
uint32_t termHeightRows
Definition: ssh_request.h:83
"signal" channel request parameters
Definition: ssh_request.h:162
SshString signalName
Definition: ssh_request.h:163
String.
Definition: ssh_types.h:56
const char_t * value
Definition: ssh_types.h:57
size_t length
Definition: ssh_types.h:58
"subsystem" channel request parameters
Definition: ssh_request.h:129
SshString subsystemName
Definition: ssh_request.h:130
"tcpip-forward" global request parameters
Definition: ssh_request.h:48
uint32_t portNumToBind
Definition: ssh_request.h:50
SshString addrToBind
Definition: ssh_request.h:49
"window-change" channel request parameters
Definition: ssh_request.h:139
uint8_t length
Definition: tcp.h:368