shell_server_misc.c
Go to the documentation of this file.
1 /**
2  * @file shell_server_misc.c
3  * @brief Helper functions for SSH secure shell server
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 SHELL_TRACE_LEVEL
33 
34 //Dependencies
35 #include "ssh/ssh.h"
36 #include "ssh/ssh_request.h"
37 #include "ssh/ssh_misc.h"
38 #include "shell/shell_server.h"
39 #include "shell/shell_server_pty.h"
41 #include "debug.h"
42 
43 //Check SSH stack configuration
44 #if (SHELL_SERVER_SUPPORT == ENABLED)
45 
46 
47 /**
48  * @brief Handle periodic operations
49  * @param[in] context Pointer to the shell server context
50  **/
51 
53 {
54 }
55 
56 
57 /**
58  * @brief SSH channel request callback
59  * @param[in] channel Handle referencing an SSH channel
60  * @param[in] type Request type
61  * @param[in] data Request-specific data
62  * @param[in] length Length of the request-specific data, in bytes
63  * @param[in] param Pointer to the shell server context
64  * @return Error code
65  **/
66 
68  const SshString *type, const uint8_t *data, size_t length,
69  void *param)
70 {
71  error_t error;
72  ShellAccessStatus status;
73  ShellServerContext *context;
74  ShellServerSession *session;
75 
76  //Debug message
77  TRACE_INFO("Shell server: SSH channel request callback...\r\n");
78 
79  //Initialize status code
80  error = NO_ERROR;
81 
82  //Point to the shell server context
83  context = (ShellServerContext *) param;
84 
85  //Check request type
86  if(sshCompareString(type, "pty-req"))
87  {
88  SshPtyReqParams requestParams;
89 
90  //Parse type-specific data
91  error = sshParsePtyReqParams(data, length, &requestParams);
92 
93  //Successful parsing?
94  if(!error)
95  {
96  //Retrieve the session that matches the channel number
97  session = shellServerFindSession(context, channel);
98 
99  //If no matching session exists, a new session is started
100  if(session == NULL)
101  {
102  //Allocate a new session
103  session = shellServerOpenSession(context, channel);
104  }
105 
106  //Valid session handle?
107  if(session != NULL)
108  {
109  //All encoded terminal modes passed in a pty request are encoded
110  //into a byte stream (refer to RFC 4254, section 8)
111  shellServerParseTermModes(session, requestParams.termModes.value,
112  requestParams.termModes.length);
113 
114  //Zero dimension parameters must be ignored (refer to RFC 4254,
115  //section 6.2)
116  if(requestParams.termWidthChars > 0)
117  {
118  //Save the terminal width (in characters)
119  session->termWidth = requestParams.termWidthChars;
120  }
121 
122  //Zero dimension parameters must be ignored (refer to RFC 4254,
123  //section 6.2)
124  if(requestParams.termHeightRows > 0)
125  {
126  //Save terminal height (in rows)
127  session->termHeight = requestParams.termHeightRows;
128  }
129  }
130  else
131  {
132  //The session table runs out of resources
133  error = ERROR_OUT_OF_RESOURCES;
134  }
135  }
136  }
137  else if(sshCompareString(type, "env"))
138  {
139  //Environment variables may be passed to the shell/command to be
140  //started later
141  }
142  else if(sshCompareString(type, "shell"))
143  {
144  //Check the length of the type-specific data
145  if(length == 0)
146  {
147  //Retrieve the session that matches the channel number
148  session = shellServerFindSession(context, channel);
149 
150  //If no matching session exists, a new session is started
151  if(session == NULL)
152  {
153  //Allocate a new session
154  session = shellServerOpenSession(context, channel);
155  }
156 
157  //Valid session handle?
158  if(session != NULL)
159  {
160  //Check session state
161  if(session->state == SHELL_SERVER_SESSION_STATE_INIT)
162  {
163  //Invoke user-defined callback, if any
164  if(context->checkUserCallback != NULL)
165  {
166  //Check user name
167  status = context->checkUserCallback(session,
168  channel->connection->user);
169  }
170  else
171  {
172  status = SHELL_ACCESS_ALLOWED;
173  }
174 
175  //Check if user is granted access to the shell
176  if(status == SHELL_ACCESS_ALLOWED)
177  {
178  //Set initial session state
179  session->state = SHELL_SERVER_SESSION_STATE_OPEN;
180  //Start executing user commands
181  osSetEvent(&session->startEvent);
182  }
183  else
184  {
185  //Access denied
186  shellServerCloseSession(session);
187  }
188  }
189  else
190  {
191  //Only one of the "shell", "exec" and "subsystem" requests can
192  //succeed per channel (refer to RFC 4254, section 6.5)
193  error = ERROR_WRONG_STATE;
194  }
195  }
196  else
197  {
198  //The session table runs out of resources
199  error = ERROR_OUT_OF_RESOURCES;
200  }
201  }
202  else
203  {
204  //The request must not contain type-specific data
205  error = ERROR_INVALID_MESSAGE;
206  }
207  }
208  else if(sshCompareString(type, "exec"))
209  {
210  SshString arg;
211  SshExecParams requestParams;
212 
213  //This message will request that the server start the execution of the
214  //given command
215  error = sshParseExecParams(data, length, &requestParams);
216 
217  //Successful parsing?
218  if(!error)
219  {
220  //Check the first argument of the command line
221  if(sshGetExecArg(&requestParams, 0, &arg) &&
222  sshCompareString(&arg, "scp"))
223  {
224  //Always reject SCP requests
225  error = ERROR_UNKNOWN_REQUEST;
226  }
227  else
228  {
229  //Check the length of the command line
230  if(requestParams.command.length < SHELL_SERVER_BUFFER_SIZE)
231  {
232  //Retrieve the session that matches the channel number
233  session = shellServerFindSession(context, channel);
234 
235  //If no matching session exists, a new session is started
236  if(session == NULL)
237  {
238  //Allocate a new session
239  session = shellServerOpenSession(context, channel);
240  }
241 
242  //Valid session handle?
243  if(session != NULL)
244  {
245  //Check session state
246  if(session->state == SHELL_SERVER_SESSION_STATE_INIT)
247  {
248  //Invoke user-defined callback, if any
249  if(context->checkUserCallback != NULL)
250  {
251  //Check user name
252  status = context->checkUserCallback(session,
253  channel->connection->user);
254  }
255  else
256  {
257  status = SHELL_ACCESS_ALLOWED;
258  }
259 
260  //Check if user is granted access to the shell
261  if(status == SHELL_ACCESS_ALLOWED)
262  {
263  //Set initial session state
264  session->state = SHELL_SERVER_SESSION_STATE_EXEC;
265 
266  //Copy command string
267  osMemcpy(session->buffer, requestParams.command.value,
268  requestParams.command.length);
269 
270  //Properly terminate the string with a NULL character
271  session->buffer[requestParams.command.length] = '\0';
272  //Save the length of the command
273  session->bufferLen = requestParams.command.length;
274 
275  //Start the execution of the given command
276  osSetEvent(&session->startEvent);
277  }
278  else
279  {
280  //Access denied
281  shellServerCloseSession(session);
282  }
283  }
284  else
285  {
286  //Only one of the "shell", "exec" and "subsystem" requests
287  //can succeed per channel (refer to RFC 4254, section 6.5)
288  error = ERROR_WRONG_STATE;
289  }
290  }
291  else
292  {
293  //The session table runs out of resources
294  error = ERROR_OUT_OF_RESOURCES;
295  }
296  }
297  else
298  {
299  //The command line is too long
300  error = ERROR_INVALID_LENGTH;
301  }
302  }
303  }
304  }
305  else if(sshCompareString(type, "window-change"))
306  {
307  SshWindowChangeParams requestParams;
308 
309  //When the window (terminal) size changes on the client side, it may
310  //send a message to the other side to inform it of the new dimensions
311  error = sshParseWindowChangeParams(data, length, &requestParams);
312 
313  //Successful parsing?
314  if(!error)
315  {
316  //Retrieve the session that matches the channel number
317  session = shellServerFindSession(context, channel);
318 
319  //Any active session found?
320  if(session != NULL)
321  {
322  //Check whether the terminal has been resized
323  if(requestParams.termWidthChars != session->termWidth ||
324  requestParams.termHeightRows != session->termHeight)
325  {
326  //Zero dimension parameters must be ignored (refer to RFC 4254,
327  //section 6.2)
328  if(requestParams.termWidthChars > 0)
329  {
330  //Save the new terminal width (in characters)
331  session->newTermWidth = requestParams.termWidthChars;
332  }
333 
334  //Zero dimension parameters must be ignored (refer to RFC 4254,
335  //section 6.2)
336  if(requestParams.termHeightRows > 0)
337  {
338  //Save the new terminal height (in rows)
339  session->newTermHeight = requestParams.termHeightRows;
340  }
341 
342  //Notify the application of the window resize event
343  session->windowResize = TRUE;
344  osSetEvent(&session->event);
345  }
346  }
347  }
348  }
349  else if(sshCompareString(type, "signal"))
350  {
351  SshSignalParams requestParams;
352 
353  //Parse type-specific data
354  error = sshParseSignalParams(data, length, &requestParams);
355  }
356  else if(sshCompareString(type, "break"))
357  {
358  SshBreakParams requestParams;
359 
360  //Parse type-specific data
361  error = sshParseBreakParams(data, length, &requestParams);
362  }
363  else
364  {
365  //The request is not supported
366  error = ERROR_UNKNOWN_REQUEST;
367  }
368 
369  //Return status code
370  return error;
371 }
372 
373 
374 /**
375  * @brief Find the shell session that matches a given SSH channel
376  * @param[in] context Pointer to the shell server context
377  * @param[in] channel Handle referencing an SSH channel
378  * @return Pointer to the matching shell session
379  **/
380 
382  SshChannel *channel)
383 {
384  uint_t i;
385  ShellServerSession *session;
386 
387  //Loop through shell sessions
388  for(i = 0; i < context->numSessions; i++)
389  {
390  //Point to the current session
391  session = &context->sessions[i];
392 
393  //Active session?
394  if(session->state != SHELL_SERVER_SESSION_STATE_CLOSED)
395  {
396  //Matching channel found?
397  if(session->channel == channel)
398  {
399  return session;
400  }
401  }
402  }
403 
404  //The channel number does not match any active session
405  return NULL;
406 }
407 
408 
409 /**
410  * @brief Open a new shell session
411  * @param[in] context Pointer to the shell server context
412  * @param[in] channel Handle referencing an SSH channel
413  * @return Pointer to the newly created shell session
414  **/
415 
417  SshChannel *channel)
418 {
419  uint_t i;
420  ShellServerSession *session;
421 
422  //Initialize pointer
423  session = NULL;
424 
425  //Prefer sessions in CLOSED state
426  for(i = 0; i < context->numSessions; i++)
427  {
428  //Check whether the current session is free
429  if(context->sessions[i].state == SHELL_SERVER_SESSION_STATE_CLOSED)
430  {
431  //Point to the current session
432  session = &context->sessions[i];
433  break;
434  }
435  }
436 
437  //Reuse orphan sessions in INIT state, if necessary
438  if(session == NULL)
439  {
440  //Loop through shell sessions
441  for(i = 0; i < context->numSessions; i++)
442  {
443  //Check whether the current session can be reused
444  if(context->sessions[i].state == SHELL_SERVER_SESSION_STATE_INIT)
445  {
446  //Point to the current session
447  session = &context->sessions[i];
448  break;
449  }
450  }
451  }
452 
453  //Valid session?
454  if(session != NULL)
455  {
456  //Attach shell server context
457  session->context = context;
458  //Attach SSH channel
459  session->channel = channel;
460 
461  //Default shell prompt
462  osStrcpy(session->prompt, ">");
463  //Save the length of the prompt string
464  session->promptLen = osStrlen(session->prompt);
465 
466  //Initialize session parameters
467  session->backspaceCode = VT100_DEL_CODE;
468  session->deleteCode = VT100_BS_CODE;
469  session->termWidth = SHELL_SERVER_DEFAULT_TERM_WIDTH;
470  session->termHeight = SHELL_SERVER_DEFAULT_TERM_HEIGHT;
471  session->newTermWidth = SHELL_SERVER_DEFAULT_TERM_WIDTH;
472  session->newTermHeight = SHELL_SERVER_DEFAULT_TERM_HEIGHT;
473 
474  //Initialize variables
475  session->bufferPos = 0;
476  session->bufferLen = 0;
477  session->windowResize = FALSE;
478  session->escSeqLen = 0;
479 
480 #if (SHELL_SERVER_HISTORY_SUPPORT == ENABLED)
481  //Clear command history
482  session->historyPos = 0;
483  session->historyLen = 0;
484 #endif
485 
486  //Set initial session state
487  session->state = SHELL_SERVER_SESSION_STATE_INIT;
488  }
489 
490  //Return a pointer to the newly created shell session, if any
491  return session;
492 }
493 
494 
495 /**
496  * @brief Close a shell session
497  * @param[in] session Handle referencing a shell session
498  **/
499 
501 {
502  //Debug message
503  TRACE_INFO("Closing shell session...\r\n");
504 
505  //Close SSH channel
506  sshCloseChannel(session->channel);
507  session->channel = NULL;
508 
509  //Mark the current session as closed
510  session->state = SHELL_SERVER_SESSION_STATE_CLOSED;
511 }
512 
513 
514 /**
515  * @brief Parse encoded terminal modes
516  * @param[in] session Handle referencing an shell session
517  * @param[in] termModes Encoded terminal modes
518  * @param[in] length Length of the encoded terminal modes, in bytes
519  * @return Error code
520  **/
521 
523  const uint8_t *termModes, size_t length)
524 {
525  error_t error;
526  size_t i;
527 
528  //Initialize status code
529  error = NO_ERROR;
530 
531  //All encoded terminal modes passed in a pty request are encoded into a
532  //byte stream (refer to RFC 4254, section 8)
533  for(i = 0; i < length && !error; i++)
534  {
535  //The stream consists of opcode-argument pairs wherein the opcode is
536  //a byte value
537  if(termModes[i] == 0)
538  {
539  //The stream is terminated by opcode TTY_OP_END
540  break;
541  }
542  else if(termModes[i] >= 1 && termModes[i] <= 159)
543  {
544  //Opcodes 1 to 159 have a single uint32 argument
545  if((i + sizeof(uint32_t)) < length)
546  {
547  //Check mnemonic
548  if(termModes[i] == SHELL_TERM_MODE_VERASE)
549  {
550  //Set backspace key code
551  session->backspaceCode = LOAD32BE(termModes + i + 1);
552 
553  //Set delete key code
554  if(session->backspaceCode == VT100_BS_CODE)
555  {
556  session->deleteCode = VT100_DEL_CODE;
557  }
558  }
559 
560  //Jump to the next opcode-argument pair
561  i += sizeof(uint32_t);
562  }
563  else
564  {
565  //The opcode-argument pair is not valid
566  error = ERROR_INVALID_SYNTAX;
567  }
568  }
569  else
570  {
571  //Opcodes 160 to 255 are not yet defined, and cause parsing to stop
572  break;
573  }
574  }
575 
576  //Return status code
577  return error;
578 }
579 
580 
581 /**
582  * @brief Command line processing
583  * @param[in] session Handle referencing an shell session
584  * @param[in] commandLine NULL-terminated string that contains the command line
585  * @return error code
586  **/
587 
589  char_t *commandLine)
590 {
591  error_t error;
592  ShellServerContext *context;
593 
594  //Point to the shell server context
595  context = session->context;
596 
597  //Invoke user-defined callback, if any
598  if(context->commandLineCallback != NULL)
599  {
600  //Process the received command line
601  error = context->commandLineCallback(session, commandLine);
602  }
603  else
604  {
605  //Discard the command line
606  error = NO_ERROR;
607  }
608 
609  //Return status code
610  return error;
611 }
612 
613 
614 /**
615  * @brief Add command line to history
616  * @param[in] session Handle referencing an shell session
617  * @param[in] commandLine NULL-terminated string that contains the command line
618  **/
619 
621  const char_t *commandLine)
622 {
623 #if (SHELL_SERVER_HISTORY_SUPPORT == ENABLED)
624  size_t i;
625  size_t j;
626  size_t n;
627 
628  //Retrieve the length of the command line
629  n = osStrlen(commandLine);
630 
631  //Valid command line?
632  if(n > 0 && n < SHELL_SERVER_HISTORY_SIZE)
633  {
634  //Point to the first entry
635  i = 0;
636 
637  //Remove duplicate entries from command history
638  while(i < session->historyLen)
639  {
640  //Save current index
641  j = i;
642 
643  //Each entry is terminated by a NULL character
644  while(i < session->historyLen && session->history[i] != '\0')
645  {
646  i++;
647  }
648 
649  //Check whether the current entry is a duplicate
650  if((i - j) == n && osMemcmp(session->history + j, commandLine, n) == 0)
651  {
652  //Skip the NULL terminator
653  if(i < session->historyLen)
654  {
655  i++;
656  }
657 
658  //Remove the duplicate entry
659  osMemmove(session->history + j, session->history + i,
660  session->historyLen - i);
661 
662  //Adjust the length of the command history buffer
663  session->historyLen -= i - j;
664  }
665  else
666  {
667  //Skip the NULL terminator
668  i++;
669  }
670  }
671 
672  //Rewind to the first entry
673  i = 0;
674 
675  //The oldest commands are discarded when the command history buffer runs
676  //out of space
677  while((session->historyLen + n + 1 - i) > SHELL_SERVER_HISTORY_SIZE)
678  {
679  //Each entry is terminated by a NULL character
680  while(i < session->historyLen && session->history[i] != '\0')
681  {
682  i++;
683  }
684 
685  //Skip the NULL terminator
686  if(i < session->historyLen)
687  {
688  i++;
689  }
690  }
691 
692  //Make room for the new entry
693  if(i > 0)
694  {
695  //Delete the oldest entries
696  osMemmove(session->history, session->history + i, session->historyLen - i);
697  //Adjust the length of the command history buffer
698  session->historyLen -= i;
699  }
700 
701  //Add command line to history
702  osMemcpy(session->history + session->historyLen, commandLine, n);
703  //Properly terminate the new entry with a NULL character
704  session->history[session->historyLen + n] = '\0';
705  //Adjust the length of the command history buffer
706  session->historyLen += n + 1;
707  }
708 
709  //Change current position in history
710  session->historyPos = session->historyLen;
711 #endif
712 }
713 
714 
715 /**
716  * @brief Extract previous command line from history
717  * @param[in] session Handle referencing an shell session
718  * @param[out] commandLine Pointer to the previous command line
719  * @param[out] length Length of the command line
720  * @return error code
721  **/
722 
724  const char_t **commandLine, size_t *length)
725 {
726 #if (SHELL_SERVER_HISTORY_SUPPORT == ENABLED)
727  error_t error;
728  size_t i;
729 
730  //Check current position in history
731  if(session->historyPos > 0)
732  {
733  //Point to the last character of the previous entry
734  i = session->historyPos - 1;
735 
736  //Entries are separated with a NULL character
737  while(i > 0 && session->history[i - 1] != '\0')
738  {
739  i--;
740  }
741 
742  //Extract the previous command line
743  *commandLine = session->history + i;
744  *length = osStrlen(session->history + i);
745 
746  //Change current position in history
747  session->historyPos = i;
748 
749  //Successful processing
750  error = NO_ERROR;
751  }
752  else
753  {
754  //The oldest entry has been reached
755  error = ERROR_NOT_FOUND;
756  }
757 
758  //Return status code
759  return error;
760 #else
761  //Not implemented
762  return ERROR_NOT_IMPLEMENTED;
763 #endif
764 }
765 
766 
767 /**
768  * @brief Extract next command line from history
769  * @param[in] session Handle referencing an shell session
770  * @param[out] commandLine Pointer to the next command line
771  * @param[out] length Length of the command line
772  * @return error code
773  **/
774 
776  const char_t **commandLine, size_t *length)
777 {
778 #if (SHELL_SERVER_HISTORY_SUPPORT == ENABLED)
779  error_t error;
780  size_t i;
781 
782  //Get current position in history
783  i = session->historyPos;
784 
785  //Each entry is terminated by a NULL character
786  while(i < session->historyLen && session->history[i] != '\0')
787  {
788  i++;
789  }
790 
791  //Skip the NULL terminator
792  if(i < session->historyLen)
793  {
794  i++;
795  }
796 
797  //Next command line found?
798  if(i < session->historyLen)
799  {
800  //Extract the next command line
801  *commandLine = session->history + i;
802  *length = osStrlen(session->history + i);
803 
804  //Change current position in history
805  session->historyPos = i;
806 
807  //Successful processing
808  error = NO_ERROR;
809  }
810  else
811  {
812  //The most recent entry has been reached
813  error = ERROR_NOT_FOUND;
814  }
815 
816  //Return status code
817  return error;
818 #else
819  //Not implemented
820  return ERROR_NOT_IMPLEMENTED;
821 #endif
822 }
823 
824 
825 /**
826  * @brief Extract first command line from history
827  * @param[in] session Handle referencing an shell session
828  * @param[out] commandLine Pointer to the first command line
829  * @param[out] length Length of the command line
830  * @return error code
831  **/
832 
834  const char_t **commandLine, size_t *length)
835 {
836 #if (SHELL_SERVER_HISTORY_SUPPORT == ENABLED)
837  error_t error;
838 
839  //Check current position in history
840  if(session->historyPos > 0)
841  {
842  //Extract the first command line
843  *commandLine = session->history;
844  *length = osStrlen(session->history);
845 
846  //Change current position in history
847  session->historyPos = 0;
848 
849  //Successful processing
850  error = NO_ERROR;
851  }
852  else
853  {
854  //The oldest entry has been reached
855  error = ERROR_NOT_FOUND;
856  }
857 
858  //Return status code
859  return error;
860 #else
861  //Not implemented
862  return ERROR_NOT_IMPLEMENTED;
863 #endif
864 }
865 
866 
867 /**
868  * @brief Extract last command line from history
869  * @param[in] session Handle referencing an shell session
870  * @param[out] commandLine Pointer to the last command line
871  * @param[out] length Length of the command line
872  * @return error code
873  **/
874 
876  const char_t **commandLine, size_t *length)
877 {
878 #if (SHELL_SERVER_HISTORY_SUPPORT == ENABLED)
879  error_t error;
880  size_t i;
881 
882  //Any entry found in command history?
883  if(session->historyLen > 0)
884  {
885  //Point to the last character of the last entry
886  i = session->historyLen - 1;
887 
888  //Entries are separated with a NULL character
889  while(i > 0 && session->history[i - 1] != '\0')
890  {
891  i--;
892  }
893 
894  //Extract the last command line
895  *commandLine = session->history + i;
896  *length = osStrlen(session->history + i);
897 
898  //Change current position in history
899  session->historyPos = i;
900 
901  //Successful processing
902  error = NO_ERROR;
903  }
904  else
905  {
906  //The command history is empty
907  error = ERROR_NOT_FOUND;
908  }
909 
910  //Return status code
911  return error;
912 #else
913  //Not implemented
914  return ERROR_NOT_IMPLEMENTED;
915 #endif
916 }
917 
918 #endif
uint8_t type
Definition: coap_common.h:176
unsigned int uint_t
Definition: compiler_port.h:50
char char_t
Definition: compiler_port.h:48
#define LOAD32BE(p)
Definition: cpu_endian.h:210
Debugging facilities.
#define TRACE_INFO(...)
Definition: debug.h:95
uint8_t n
error_t
Error codes.
Definition: error.h:43
@ ERROR_NOT_FOUND
Definition: error.h:147
@ ERROR_OUT_OF_RESOURCES
Definition: error.h:64
@ ERROR_INVALID_MESSAGE
Definition: error.h:105
@ ERROR_INVALID_SYNTAX
Definition: error.h:68
@ ERROR_NOT_IMPLEMENTED
Definition: error.h:66
@ ERROR_UNKNOWN_REQUEST
Definition: error.h:276
@ NO_ERROR
Success.
Definition: error.h:44
@ ERROR_WRONG_STATE
Definition: error.h:209
@ ERROR_INVALID_LENGTH
Definition: error.h:111
uint8_t data[]
Definition: ethernet.h:222
#define osMemmove(dest, src, length)
Definition: os_port.h:147
#define osMemcpy(dest, src, length)
Definition: os_port.h:141
#define osMemcmp(p1, p2, length)
Definition: os_port.h:153
#define osStrlen(s)
Definition: os_port.h:165
#define TRUE
Definition: os_port.h:50
#define FALSE
Definition: os_port.h:46
#define osStrcpy(s1, s2)
Definition: os_port.h:207
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
SSH secure shell server.
@ SHELL_SERVER_SESSION_STATE_INIT
Definition: shell_server.h:147
@ SHELL_SERVER_SESSION_STATE_OPEN
Definition: shell_server.h:148
@ SHELL_SERVER_SESSION_STATE_EXEC
Definition: shell_server.h:149
@ SHELL_SERVER_SESSION_STATE_CLOSED
Definition: shell_server.h:146
#define SHELL_SERVER_DEFAULT_TERM_HEIGHT
Definition: shell_server.h:107
#define SHELL_SERVER_BUFFER_SIZE
Definition: shell_server.h:72
ShellAccessStatus
Access status.
Definition: shell_server.h:134
@ SHELL_ACCESS_ALLOWED
Definition: shell_server.h:136
#define ShellServerSession
Definition: shell_server.h:121
#define SHELL_SERVER_DEFAULT_TERM_WIDTH
Definition: shell_server.h:100
#define ShellServerContext
Definition: shell_server.h:117
#define SHELL_SERVER_HISTORY_SIZE
Definition: shell_server.h:86
error_t shellServerGetFirstCommandLine(ShellServerSession *session, const char_t **commandLine, size_t *length)
Extract first command line from history.
ShellServerSession * shellServerOpenSession(ShellServerContext *context, SshChannel *channel)
Open a new shell session.
error_t shellServerParseTermModes(ShellServerSession *session, const uint8_t *termModes, size_t length)
Parse encoded terminal modes.
error_t shellServerChannelRequestCallback(SshChannel *channel, const SshString *type, const uint8_t *data, size_t length, void *param)
SSH channel request callback.
void shellServerCloseSession(ShellServerSession *session)
Close a shell session.
void shellServerTick(ShellServerContext *context)
Handle periodic operations.
error_t shellServerGetPrevCommandLine(ShellServerSession *session, const char_t **commandLine, size_t *length)
Extract previous command line from history.
error_t shellServerGetLastCommandLine(ShellServerSession *session, const char_t **commandLine, size_t *length)
Extract last command line from history.
error_t shellServerProcessCommandLine(ShellServerSession *session, char_t *commandLine)
Command line processing.
ShellServerSession * shellServerFindSession(ShellServerContext *context, SshChannel *channel)
Find the shell session that matches a given SSH channel.
error_t shellServerGetNextCommandLine(ShellServerSession *session, const char_t **commandLine, size_t *length)
Extract next command line from history.
void shellServerAddCommandLine(ShellServerSession *session, const char_t *commandLine)
Add command line to history.
Helper functions for SSH secure shell server.
Pseudo-terminal emulation.
#define VT100_DEL_CODE
#define VT100_BS_CODE
@ SHELL_TERM_MODE_VERASE
error_t sshCloseChannel(SshChannel *channel)
Close channel.
Definition: ssh.c:2465
Secure Shell (SSH)
#define SshChannel
Definition: ssh.h:887
bool_t sshCompareString(const SshString *string, const char_t *value)
Compare a binary string against the supplied value.
Definition: ssh_misc.c:1586
SSH helper functions.
error_t sshParseSignalParams(const uint8_t *p, size_t length, SshSignalParams *params)
Parse "signal" channel request parameters.
Definition: ssh_request.c:1680
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 sshParseBreakParams(const uint8_t *p, size_t length, SshBreakParams *params)
Parse "break" channel request parameters.
Definition: ssh_request.c:1733
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 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.
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
"exec" channel request parameters
Definition: ssh_request.h:119
SshString command
Definition: ssh_request.h:120
"pty-req" channel request parameters
Definition: ssh_request.h:80
SshBinaryString termModes
Definition: ssh_request.h:86
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
String.
Definition: ssh_types.h:56
const char_t * value
Definition: ssh_types.h:57
size_t length
Definition: ssh_types.h:58
"window-change" channel request parameters
Definition: ssh_request.h:139
uint8_t length
Definition: tcp.h:368