You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
	
	
		
			723 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			C
		
	
		
		
			
		
	
	
			723 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			C
		
	
|   
											2 months ago
										 | /*****************************************************************************
 | ||
|  |  * file    lib/management/cmd_SSH2.c   | ||
|  |  * author  YuLiang | ||
|  |  * version 1.0.0 | ||
|  |  * date    20-Mar-2025 | ||
|  |  * brief   This file provides all the SSH2 cmd related operation functions. | ||
|  |  ****************************************************************************** | ||
|  |  * Attention | ||
|  |  * | ||
|  |  * <h2><center>© COPYRIGHT(c) 2025 LandPower</center></h2> | ||
|  |  * | ||
|  |  * Redistribution and use in source and binary forms, with or without modification, | ||
|  |  * are permitted provided that the following conditions are met: | ||
|  |  *   1. Redistributions of source code must retain the above copyright notice, | ||
|  |  *      this list of conditions and the following disclaimer. | ||
|  |  *   2. Redistributions in binary form must reproduce the above copyright notice, | ||
|  |  *      this list of conditions and the following disclaimer in the documentation | ||
|  |  *      and/or other materials provided with the distribution. | ||
|  |  *   3. Neither the name of LandPower nor the names of its contributors may be used to  | ||
|  |  *      endorse or promote products derived from this software without specific | ||
|  |  *      prior written permission. | ||
|  |  * | ||
|  |  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
|  |  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
|  |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
|  |  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | ||
|  |  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
|  |  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
|  |  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||
|  |  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||
|  |  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
|  |  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
|  |  * | ||
|  |  ******************************************************************************/ | ||
|  | 
 | ||
|  | /* Includes ------------------------------------------------------------------*/ | ||
|  | //#ifdef HAVE_CONFIG_H
 | ||
|  | #include "config.h"
 | ||
|  | //#endif
 | ||
|  | 
 | ||
|  | /* 标准C库头文件. */ | ||
|  | #include <ctype.h>
 | ||
|  | #include <libssh/libssh.h>
 | ||
|  | #include <libssh/server.h>
 | ||
|  | #include <libssh/callbacks.h>
 | ||
|  | 
 | ||
|  | /* 用户代码头文件. */ | ||
|  | #include "main.h"
 | ||
|  | #include "vty.h"
 | ||
|  | #include "cmd.h"
 | ||
|  | #include "mtimer.h"
 | ||
|  | 
 | ||
|  | /* Private typedef -----------------------------------------------------------*/ | ||
|  | 
 | ||
|  | /* Private define ------------------------------------------------------------*/ | ||
|  | #define VTYCMD_PORT "2222"
 | ||
|  | #define VTYCMD_RSA_PATH "/home/root/ssh/ssh_host_rsa_key"
 | ||
|  | #define VTYCMD_HOSTKEY_PATH "/home/root/ssh/ssh_host_ed25519_key"
 | ||
|  | 
 | ||
|  | #define VTYCMD_BUF_OUT_LEN 32768
 | ||
|  | 
 | ||
|  | typedef struct _vtycmd_ctrl | ||
|  | { | ||
|  |     vty_t *vtycmd; | ||
|  |     ssh_bind sshbind; | ||
|  |     ssh_session session; | ||
|  |     ssh_channel channel; | ||
|  |     struct ssh_server_callbacks_struct server_cb; | ||
|  |     struct ssh_channel_callbacks_struct channel_cb; | ||
|  |     uint8_t is_connect;  | ||
|  |     uint8_t is_recv; | ||
|  |     uint16_t cmd_idx; | ||
|  |     char cmd[VTY_BUFSIZ]; | ||
|  |     uint16_t out_buf_start; | ||
|  |     uint16_t out_buf_end; | ||
|  |     char out_buf[VTYCMD_BUF_OUT_LEN]; | ||
|  | } vtycmd_ctrl_t; | ||
|  | 
 | ||
|  | /* Private macro -------------------------------------------------------------*/ | ||
|  | 
 | ||
|  | /* Private variables ---------------------------------------------------------*/ | ||
|  | /* cmd vty结构体. */ | ||
|  | static vtycmd_ctrl_t vtycmd_ctrl; | ||
|  | 
 | ||
|  | /* Private function prototypes -----------------------------------------------*/ | ||
|  | /* 在终端上显示当前配置信息. */ | ||
|  | CMD(show_sshcmd, | ||
|  |     show_sshcmd_cmd, | ||
|  |     "show sshcmd", | ||
|  |     SHOW_STR | ||
|  |     "SSHCMD\n") | ||
|  | { | ||
|  |     vty_out(vty, "Connect: %s\r\n\n", vtycmd_ctrl.is_connect ? "yes" : "no"); | ||
|  | 
 | ||
|  |     return CMD_SUCCESS; | ||
|  | } | ||
|  | 
 | ||
|  | /* Insert a word into vty interface with overwrite mode. */ | ||
|  | void _vtycmd_insert_word(char *str) | ||
|  | { | ||
|  |     int len = strlen(str); | ||
|  | 
 | ||
|  |     ssh_channel_write(vtycmd_ctrl.channel, str, len); | ||
|  |     strcpy(&vtycmd_ctrl.cmd[vtycmd_ctrl.cmd_idx], str); | ||
|  |     vtycmd_ctrl.cmd_idx += len; | ||
|  |     vtycmd_ctrl.cmd[vtycmd_ctrl.cmd_idx] = 0; | ||
|  | } | ||
|  | 
 | ||
|  | /* commandLine '?'响应函数. */ | ||
|  | int _vtycmd_question(void) | ||
|  | { | ||
|  |     array_t *cmd_line = NULL; | ||
|  | 
 | ||
|  |     cmd_line = cmd_strs_create(vtycmd_ctrl.cmd); | ||
|  |     if (NULL == cmd_line) | ||
|  |     { | ||
|  |         cmd_line = array_init(1, MTYPE_CLI); | ||
|  |         array_append(cmd_line, '\0', MTYPE_CLI); | ||
|  |     } | ||
|  |     else | ||
|  |         if (vtycmd_ctrl.cmd_idx && isspace((int)vtycmd_ctrl.cmd[vtycmd_ctrl.cmd_idx - 1])) | ||
|  |             array_append(cmd_line, '\0', MTYPE_CLI); | ||
|  | 
 | ||
|  |     vty_question(vtycmd_ctrl.vtycmd, cmd_line); | ||
|  | 
 | ||
|  |     cmd_strs_free(cmd_line); | ||
|  |     vty_prompt(vtycmd_ctrl.vtycmd); | ||
|  |     vty_out(vtycmd_ctrl.vtycmd, "%s", vtycmd_ctrl.cmd); | ||
|  |     return 0; | ||
|  | } | ||
|  | 
 | ||
|  | /* 用于自动补齐命令行关键字. */ | ||
|  | void _vtycmd_completion_append(array_t *cmd_line, char *word, int32_t status) | ||
|  | { | ||
|  |      uint32_t index = array_active(cmd_line) - 1; | ||
|  |      uint32_t len = 0; | ||
|  |      uint32_t i = 0; | ||
|  | 
 | ||
|  |     if (NULL == array_get(cmd_line, index)) | ||
|  |     { | ||
|  |         _vtycmd_insert_word(word); | ||
|  |     } | ||
|  |     else | ||
|  |     { | ||
|  |         len = strlen(array_get(cmd_line, index)); | ||
|  |         for(i = 0; i < len; i++) | ||
|  |         { | ||
|  |             if (vtycmd_ctrl.cmd_idx) | ||
|  |             { | ||
|  |                 vtycmd_ctrl.cmd_idx--; | ||
|  |                 vty_out(vtycmd_ctrl.vtycmd, "%c%c%c", 8, ' ', 8); | ||
|  |             } | ||
|  |         } | ||
|  |         _vtycmd_insert_word(word); | ||
|  |     } | ||
|  | 
 | ||
|  |     if (CMD_COMPLETE_FULL_MATCH == status) | ||
|  |         _vtycmd_insert_word(" "); | ||
|  | } | ||
|  | 
 | ||
|  | /* commandLine 'TAB'响应函数. */ | ||
|  | int _vtycmd_completion(void) | ||
|  | { | ||
|  |     array_t *cmd_line = NULL; | ||
|  |     char **match_strs = NULL; | ||
|  |     int32_t complete_status = CMD_ERR_NO_MATCH; | ||
|  | 
 | ||
|  |     cmd_line = cmd_strs_create(vtycmd_ctrl.cmd); | ||
|  |     if (NULL == cmd_line) | ||
|  |     { | ||
|  |         cmd_line = array_init(1, MTYPE_CLI); | ||
|  |         array_append(cmd_line, '\0', MTYPE_CLI); | ||
|  |     } | ||
|  |     else | ||
|  |         if (vtycmd_ctrl.cmd_idx && isspace((int)vtycmd_ctrl.cmd[vtycmd_ctrl.cmd_idx - 1])) | ||
|  |             array_append(cmd_line, '\0', MTYPE_CLI); | ||
|  | 
 | ||
|  |     match_strs = cmd_complete_command(cmd_line, vtycmd_ctrl.vtycmd, &complete_status); | ||
|  |     if (NULL == match_strs) | ||
|  |     { | ||
|  |         cmd_strs_free(cmd_line); | ||
|  |         return 0; | ||
|  |     } | ||
|  | 
 | ||
|  |     if (CMD_COMPLETE_MATCH == complete_status || | ||
|  |         CMD_COMPLETE_FULL_MATCH == complete_status) | ||
|  |     { | ||
|  |         _vtycmd_completion_append(cmd_line, match_strs[0], complete_status); | ||
|  |         // if (match_strs) {
 | ||
|  |         //     fprintf(stderr, "Match strings: %s\n", match_strs[0]);
 | ||
|  |         // }
 | ||
|  |     } | ||
|  |     else | ||
|  |     { | ||
|  |         vty_print_word(vtycmd_ctrl.vtycmd, match_strs); | ||
|  |         vty_prompt(vtycmd_ctrl.vtycmd); | ||
|  |         vty_out(vtycmd_ctrl.vtycmd, "%s", vtycmd_ctrl.cmd); | ||
|  |     } | ||
|  | 
 | ||
|  |     vty_free_match_strs(match_strs); | ||
|  |     cmd_strs_free(cmd_line); | ||
|  | 
 | ||
|  |     return 0; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* Internal functions --------------------------------------------------------*/ | ||
|  | /* Print command line history.  This function is called from
 | ||
|  |    vty_next_line and vty_previous_line. */ | ||
|  | static void _vtycmd_history_print(vty_t *vty) | ||
|  | { | ||
|  |     uint16_t i= 0; | ||
|  | 
 | ||
|  |     for(i = 0; i < vtycmd_ctrl.cmd_idx; i++) | ||
|  |     { | ||
|  |         vty_out(vtycmd_ctrl.vtycmd, "%c%c%c", 8, ' ', 8); | ||
|  |     } | ||
|  |     vtycmd_ctrl.cmd_idx = 0; | ||
|  |      | ||
|  |     /* Get previous line from history buffer */ | ||
|  |     vtycmd_ctrl.cmd_idx = strlen(vty->hist[vty->hp]); | ||
|  |     memcpy(vtycmd_ctrl.cmd, vty->hist[vty->hp], vtycmd_ctrl.cmd_idx); | ||
|  |     vtycmd_ctrl.cmd[vtycmd_ctrl.cmd_idx] = 0; | ||
|  | 
 | ||
|  |     /* Redraw current line */ | ||
|  |     vty_out(vtycmd_ctrl.vtycmd, "%s", vtycmd_ctrl.cmd); | ||
|  | } | ||
|  | 
 | ||
|  | /* Show previous command line history. */ | ||
|  | static void _vtycmd_previous_line(vty_t *vty) | ||
|  | { | ||
|  |     unsigned int try_index = 0; | ||
|  | 
 | ||
|  |     try_index = vty->hp; | ||
|  |     if (try_index == 0) | ||
|  |         try_index = VTY_MAXHIST - 1; | ||
|  |     else | ||
|  |         try_index--; | ||
|  | 
 | ||
|  |     if (vty->hist[try_index] == NULL) | ||
|  |         return; | ||
|  |     else | ||
|  |         vty->hp = try_index; | ||
|  | 
 | ||
|  |     _vtycmd_history_print(vty); | ||
|  | } | ||
|  | 
 | ||
|  | /* Show next command line history. */ | ||
|  | static void _vtycmd_next_line(vty_t *vty) | ||
|  | { | ||
|  |     unsigned int try_index = 0; | ||
|  | 
 | ||
|  |     if (vty->hp == vty->hindex) | ||
|  |         return; | ||
|  | 
 | ||
|  |     /* Try is there history exist or not. */ | ||
|  |     try_index = vty->hp; | ||
|  |     if (try_index == (VTY_MAXHIST - 1)) | ||
|  |         try_index = 0; | ||
|  |     else | ||
|  |         try_index++; | ||
|  | 
 | ||
|  |     /* If there is not history return. */ | ||
|  |     if (vty->hist[try_index] == NULL) | ||
|  |         return; | ||
|  |     else | ||
|  |         vty->hp = try_index; | ||
|  | 
 | ||
|  |     _vtycmd_history_print(vty); | ||
|  | } | ||
|  | 
 | ||
|  | int _vtycmd_cmd(char *buf, uint32_t len) | ||
|  | { | ||
|  |     uint16_t i = 0; | ||
|  |     vty_t *vty = vtycmd_ctrl.vtycmd;  | ||
|  | 
 | ||
|  |     for (i = 0; i < len; i++)  | ||
|  |     { | ||
|  |         switch (buf[i]) | ||
|  |         { | ||
|  |         case '\033': | ||
|  |             if (i + 2 < len  && buf[i + 1] == '[') | ||
|  |             { | ||
|  |                 if (buf[i + 2] == 'A') | ||
|  |                 { | ||
|  |                     _vtycmd_previous_line(vty); | ||
|  |                 } | ||
|  |                 else if (buf[i + 2] == 'B') | ||
|  |                 { | ||
|  |                     _vtycmd_next_line(vty); | ||
|  |                 } | ||
|  |                 i += 2; | ||
|  |             } | ||
|  |             break; | ||
|  |         case CONTROL('H'): | ||
|  |         case 0x7f: | ||
|  |             if (vtycmd_ctrl.cmd_idx) | ||
|  |             { | ||
|  |                 vtycmd_ctrl.cmd_idx--; | ||
|  |                 vtycmd_ctrl.cmd[vtycmd_ctrl.cmd_idx] = 0; | ||
|  |                 vty_out(vty, "%c%c%c", 8, ' ', 8); | ||
|  |             } | ||
|  |             break; | ||
|  |         case '\n': | ||
|  |         case '\r': | ||
|  |             vty_out(vty, "%s", VTY_NEWLINE); | ||
|  |             /* 执行命令 */ | ||
|  |             vtycmd_ctrl.cmd[vtycmd_ctrl.cmd_idx] = 0; | ||
|  |             vty->length = vtycmd_ctrl.cmd_idx; | ||
|  |             snprintf(vty->buf, VTY_BUFSIZ, "%s", vtycmd_ctrl.cmd); | ||
|  |             vty_execute(vty); | ||
|  |             vtycmd_ctrl.cmd_idx = 0; | ||
|  |             vtycmd_ctrl.cmd[vtycmd_ctrl.cmd_idx] = 0; | ||
|  |             break; | ||
|  |         case '\t': | ||
|  |             _vtycmd_completion(); | ||
|  |             break; | ||
|  |         case '?': | ||
|  |             _vtycmd_question(); | ||
|  |             break; | ||
|  |         default: | ||
|  |             if (buf[i] > 31 && buf[i] < 127) | ||
|  |             { | ||
|  |                 vtycmd_ctrl.cmd[vtycmd_ctrl.cmd_idx] = buf[i]; | ||
|  |                 vtycmd_ctrl.cmd_idx++; | ||
|  |                 vtycmd_ctrl.cmd[vtycmd_ctrl.cmd_idx] = 0; | ||
|  |                 vty_out(vty, "%c", buf[i]); | ||
|  |             } | ||
|  |             break; | ||
|  |         } | ||
|  |     } | ||
|  |      | ||
|  |     return E_NONE; | ||
|  | } | ||
|  |      | ||
|  | /* 客户端通讯相关的回调 */ | ||
|  | int _vtycmd_channel_pty_request(ssh_session session, ssh_channel channel, | ||
|  |                 const char *term, int cols, int rows, int py, int px, | ||
|  |                 void *userdata) | ||
|  | { | ||
|  |     ssh_channel_write(vtycmd_ctrl.channel, "Username: ", 10); | ||
|  |     ssh_channel_request_pty_size(channel, term, cols, rows); | ||
|  |     return SSH_OK; | ||
|  | } | ||
|  | 
 | ||
|  | int _vtycmd_channel_pty_resize(ssh_session session, ssh_channel channel, int cols, | ||
|  |                int rows, int py, int px, void *userdata) | ||
|  | { | ||
|  |     return ssh_channel_change_pty_size(channel, cols, rows); | ||
|  | } | ||
|  | 
 | ||
|  | int _vtycmd_channel_shell_request(ssh_session session, ssh_channel channel, | ||
|  |                   void *userdata) | ||
|  | { | ||
|  |     return SSH_OK; | ||
|  | } | ||
|  | 
 | ||
|  | int _vtycmd_channel_exec_request(ssh_session session, ssh_channel channel, | ||
|  |                  const char *command, void *userdata) | ||
|  | { | ||
|  |     return ssh_channel_request_exec(channel, command); | ||
|  | } | ||
|  | 
 | ||
|  | int _vtycmd_channel_subsystem_request(ssh_session session, ssh_channel channel, | ||
|  |                       const char *subsystem, void *userdata) | ||
|  | { | ||
|  |     return  SSH_OK; | ||
|  | } | ||
|  | 
 | ||
|  | int _vtycmd_channel_env_request_function(ssh_session session, ssh_channel channel, const char *env_name, | ||
|  |                          const char *env_value, void *userdata) | ||
|  | { | ||
|  |     return ssh_channel_request_env(channel, env_name, env_value); | ||
|  | } | ||
|  | 
 | ||
|  | /* 数据处理 */ | ||
|  | int _vtycmd_channel_data_function(ssh_session session, ssh_channel channel, void *data, | ||
|  |                   uint32_t len, int is_stderr, void *userdata) | ||
|  | { | ||
|  |     vtycmd_ctrl.is_recv = TRUE; | ||
|  |     _vtycmd_cmd((char*)data, len); | ||
|  |     return len; | ||
|  | } | ||
|  | 
 | ||
|  | void _vtycmd_channel_close(ssh_session session, ssh_channel channel, void *userdata) | ||
|  | { | ||
|  |     vtycmd_ctrl.is_connect = FALSE; | ||
|  | } | ||
|  |                    | ||
|  | /* 服务端认证通道相关回调 */ | ||
|  | int _vtycmd_server_auth_pass(ssh_session session, const char *user, const char *password, void *userdata) | ||
|  | { | ||
|  |     if (strcmp("root", user) == 0 && strcmp("123456", password) == 0) | ||
|  |     { | ||
|  |         return SSH_AUTH_SUCCESS; | ||
|  |     } | ||
|  |     else | ||
|  |     { | ||
|  |         return SSH_AUTH_DENIED; | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | /* 空认证方法 */ | ||
|  | int _vtycmd_server_auth_none_callback(ssh_session session, const char *user, void *userdata) | ||
|  | { | ||
|  |     return SSH_AUTH_SUCCESS; | ||
|  | } | ||
|  | 
 | ||
|  | /* pubkey 认证方法 */ | ||
|  | int _vtycmd_server_auth_pubkey(ssh_session session, const char *user, struct ssh_key_struct *pubkey, | ||
|  |                 char signature_state, void *userdata) | ||
|  | { | ||
|  |     return SSH_AUTH_SUCCESS; | ||
|  | } | ||
|  | 
 | ||
|  | int _vtycmd_server_request_callback(ssh_session session, const char *service, void *userdata) | ||
|  | { | ||
|  |     return SSH_OK; | ||
|  | } | ||
|  | 
 | ||
|  | ssh_channel _vtycmd_server_open_channel(ssh_session session, void *userdata) | ||
|  | { | ||
|  |     vtycmd_ctrl.channel = ssh_channel_new(session); | ||
|  | 
 | ||
|  |     ssh_callbacks_init(&vtycmd_ctrl.channel_cb); | ||
|  |     ssh_set_channel_callbacks(vtycmd_ctrl.channel, &vtycmd_ctrl.channel_cb); | ||
|  |          | ||
|  |     return vtycmd_ctrl.channel; | ||
|  | } | ||
|  | 
 | ||
|  | /* SSH2 命令行主函数 */ | ||
|  | void *_vtycmd_handle(void *arg) | ||
|  | { | ||
|  |     /* 初始化 libssh */ | ||
|  |     if (ssh_init() < 0) | ||
|  |     { | ||
|  |         log_err(LOG_CLI, "ssh_init failed\r\n"); | ||
|  |         return NULL; | ||
|  |     } | ||
|  | 
 | ||
|  |     /* 初始化结构体 */ | ||
|  |     vtycmd_ctrl.server_cb.auth_password_function = _vtycmd_server_auth_pass; | ||
|  |     vtycmd_ctrl.server_cb.auth_none_function = _vtycmd_server_auth_none_callback; | ||
|  |     vtycmd_ctrl.server_cb.auth_pubkey_function = _vtycmd_server_auth_pubkey; | ||
|  |     vtycmd_ctrl.server_cb.service_request_function = _vtycmd_server_request_callback; | ||
|  |     vtycmd_ctrl.server_cb.channel_open_request_session_function = _vtycmd_server_open_channel; | ||
|  | 
 | ||
|  |     vtycmd_ctrl.channel_cb.channel_data_function = _vtycmd_channel_data_function; | ||
|  |     vtycmd_ctrl.channel_cb.channel_close_function = _vtycmd_channel_close; | ||
|  |     vtycmd_ctrl.channel_cb.channel_pty_request_function = _vtycmd_channel_pty_request; | ||
|  |     vtycmd_ctrl.channel_cb.channel_shell_request_function = _vtycmd_channel_shell_request; | ||
|  |     vtycmd_ctrl.channel_cb.channel_pty_window_change_function = _vtycmd_channel_pty_resize; | ||
|  |     vtycmd_ctrl.channel_cb.channel_exec_request_function = _vtycmd_channel_exec_request; | ||
|  |     vtycmd_ctrl.channel_cb.channel_env_request_function = _vtycmd_channel_env_request_function; | ||
|  |     vtycmd_ctrl.channel_cb.channel_subsystem_request_function = _vtycmd_channel_subsystem_request; | ||
|  | 
 | ||
|  |     /* 创建 SSH2 接口 */ | ||
|  |     vtycmd_ctrl.sshbind = ssh_bind_new(); | ||
|  |     ssh_bind_options_set(vtycmd_ctrl.sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, VTYCMD_PORT); | ||
|  |     ssh_bind_options_set(vtycmd_ctrl.sshbind, SSH_BIND_OPTIONS_RSAKEY, VTYCMD_RSA_PATH); | ||
|  |     ssh_bind_options_set(vtycmd_ctrl.sshbind, SSH_BIND_OPTIONS_HOSTKEY, VTYCMD_HOSTKEY_PATH); | ||
|  |     if (ssh_bind_listen(vtycmd_ctrl.sshbind) < 0) | ||
|  |     { | ||
|  |         log_err(LOG_CLI, "Error listening to socket: %s\n", ssh_get_error(vtycmd_ctrl.sshbind)); | ||
|  |         return NULL; | ||
|  |     } | ||
|  | 
 | ||
|  |     while(1) | ||
|  |     { | ||
|  |         /* 等待连接 */ | ||
|  |         ssh_session session = ssh_new(); | ||
|  |         if (ssh_bind_accept(vtycmd_ctrl.sshbind, session) != SSH_OK) | ||
|  |         { | ||
|  |             DBG(DBG_M_CLI, "Error accept to socket: %s\n", ssh_get_error(vtycmd_ctrl.sshbind)); | ||
|  |             continue; | ||
|  |         } | ||
|  | 
 | ||
|  |         /* 只能接收一个连接 */ | ||
|  |         if (vtycmd_ctrl.is_connect) | ||
|  |         { | ||
|  |             ssh_disconnect(session); | ||
|  |             ssh_free(session); | ||
|  |             continue; | ||
|  |         } | ||
|  | 
 | ||
|  |         /* 初始化连接 */ | ||
|  |         log_notice(LOG_CLI, "SSH2 command is connect.\n"); | ||
|  |         vtycmd_ctrl.is_connect = TRUE; | ||
|  |         ssh_callbacks_init(&vtycmd_ctrl.server_cb); | ||
|  |         ssh_set_server_callbacks(session, &vtycmd_ctrl.server_cb); | ||
|  |         ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD); | ||
|  |         if (ssh_handle_key_exchange(session) != SSH_OK) | ||
|  |         { | ||
|  |             DBG(DBG_M_CLI, "Error performing key exchange: %s\n", ssh_get_error(session)); | ||
|  |             ssh_disconnect(session); | ||
|  |             ssh_free(session); | ||
|  |             continue; | ||
|  |         } | ||
|  | 
 | ||
|  |         ssh_set_blocking(session, 0); | ||
|  |         ssh_event event = ssh_event_new(); | ||
|  |         ssh_event_add_session(event, session); | ||
|  | 
 | ||
|  |         /* 处理连接断开 */ | ||
|  |         while(1) | ||
|  |         { | ||
|  |             if (ssh_event_dopoll(event, 3000) == SSH_ERROR | ||
|  |                 || !vtycmd_ctrl.is_connect) | ||
|  |             { | ||
|  |                 /* 终端断开处理 */ | ||
|  |                 log_notice(LOG_CLI, "SSH2 command is disconnect.\n"); | ||
|  |                 ssh_channel_close(vtycmd_ctrl.channel); | ||
|  |                 ssh_channel_free(vtycmd_ctrl.channel); | ||
|  |                 ssh_disconnect(session); | ||
|  |                 ssh_event_free(event); | ||
|  |                 ssh_free(session); | ||
|  |                 vtycmd_ctrl.is_connect = FALSE; | ||
|  |                 if (CONFIG_NODE == vtycmd_ctrl.vtycmd->node) | ||
|  |                 { | ||
|  |                     vty_config_unlock(vtycmd_ctrl.vtycmd); | ||
|  |                 } | ||
|  |                 vtycmd_ctrl.vtycmd->node = USERNAME_NODE; | ||
|  |                 break; | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     return NULL; | ||
|  | } | ||
|  | 
 | ||
|  | /* 用于判断终端是否超时 */ | ||
|  | void* _vtycmd_timer(void *arg) | ||
|  | { | ||
|  |     if (!vtycmd_ctrl.is_recv && vtycmd_ctrl.is_connect) | ||
|  |     { | ||
|  |         vtycmd_ctrl.is_connect = FALSE; | ||
|  |     } | ||
|  |     vtycmd_ctrl.is_recv = FALSE; | ||
|  | 
 | ||
|  |     /* 重新加入定时器. */ | ||
|  |     mtimer_add(_vtycmd_timer, NULL, 120, "VTYCMD_TIMER"); | ||
|  |     return NULL; | ||
|  | } | ||
|  | 
 | ||
|  | /* SSH2 命令行发送数据 */ | ||
|  | void *_vtycmd_send_handle(void *arg) | ||
|  | { | ||
|  |     char *buf = NULL; | ||
|  |     uint16_t end = 0; | ||
|  |      | ||
|  |     while(1) | ||
|  |     { | ||
|  |         usleep(100000); | ||
|  |          | ||
|  |         if (!vtycmd_ctrl.is_connect) | ||
|  |         { | ||
|  |             continue; | ||
|  |         } | ||
|  |          | ||
|  |         end = vtycmd_ctrl.out_buf_end; | ||
|  |         buf = vtycmd_ctrl.out_buf + vtycmd_ctrl.out_buf_start; | ||
|  |          | ||
|  |         if (end == vtycmd_ctrl.out_buf_start) | ||
|  |         { | ||
|  |             continue; | ||
|  |         } | ||
|  |          | ||
|  |         if (end < vtycmd_ctrl.out_buf_start) | ||
|  |         { | ||
|  |             ssh_channel_write(vtycmd_ctrl.channel, buf, VTYCMD_BUF_OUT_LEN - vtycmd_ctrl.out_buf_start); | ||
|  |             vtycmd_ctrl.out_buf_start = 0; | ||
|  |         } | ||
|  |         else | ||
|  |         { | ||
|  |             ssh_channel_write(vtycmd_ctrl.channel, buf, end - vtycmd_ctrl.out_buf_start); | ||
|  |             vtycmd_ctrl.out_buf_start = end; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     return NULL; | ||
|  | } | ||
|  | 
 | ||
|  | /* Interface functions -------------------------------------------------------*/ | ||
|  | /* 初始化 SSH2 命令行 */ | ||
|  | void vtycmd_init(void) | ||
|  | {    | ||
|  |     /* Make vty structure. */ | ||
|  |     vtycmd_ctrl.vtycmd = vty_create(); | ||
|  |     vtycmd_ctrl.vtycmd->type = VTY_CMD; | ||
|  |     vtycmd_ctrl.vtycmd->node = USERNAME_NODE; | ||
|  |     memset(vtycmd_ctrl.vtycmd->hist, 0, sizeof(vtycmd_ctrl.vtycmd->hist)); | ||
|  |     vtycmd_ctrl.vtycmd->hp = 0; | ||
|  |     vtycmd_ctrl.vtycmd->hindex = 0; | ||
|  | 
 | ||
|  |     cmd_install_element(COMMON_NODE, &show_sshcmd_cmd); | ||
|  | } | ||
|  | 
 | ||
|  | /* 启动 SSH2 命令行 */ | ||
|  | void vtycmd_cmd_init(void) | ||
|  | { | ||
|  |     pthread_t pid; | ||
|  |     struct sched_param param; | ||
|  |     pthread_attr_t attr; | ||
|  |     int32_t rv = 0; | ||
|  | 
 | ||
|  |     /* 配置线程RR调度, 优先级75 */ | ||
|  |     pthread_attr_init(&attr); | ||
|  |     param.sched_priority = 75; | ||
|  |     pthread_attr_setschedpolicy(&attr, SCHED_RR); | ||
|  |     pthread_attr_setschedparam(&attr, ¶m); | ||
|  |     pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); | ||
|  | 
 | ||
|  |     rv = pthread_create(&pid, &attr, _vtycmd_handle, NULL); | ||
|  |     if (rv != 0) | ||
|  |     { | ||
|  |         log_err(LOG_DEFAULT, "vtycmd_cmd_init can't create pthread %d!", rv); | ||
|  |     } | ||
|  |     else | ||
|  |     { | ||
|  |         thread_m_add("CMD", pid); | ||
|  |     } | ||
|  |     pthread_attr_destroy(&attr); | ||
|  | 
 | ||
|  |     mtimer_add(_vtycmd_timer, NULL, 120, "VTYCMD_TIMER"); | ||
|  | 
 | ||
|  |     /* 配置线程RR调度, 优先级75 */ | ||
|  |     pthread_attr_init(&attr); | ||
|  |     param.sched_priority = 75; | ||
|  |     pthread_attr_setschedpolicy(&attr, SCHED_RR); | ||
|  |     pthread_attr_setschedparam(&attr, ¶m); | ||
|  |     pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); | ||
|  | 
 | ||
|  |     rv = pthread_create(&pid, &attr, _vtycmd_send_handle, NULL); | ||
|  |     if (rv != 0) | ||
|  |     { | ||
|  |         log_err(LOG_DEFAULT, "vtycmd_cmd_init can't create pthread %d!", rv); | ||
|  |     } | ||
|  |     else | ||
|  |     { | ||
|  |         thread_m_add("CMD_SNED", pid); | ||
|  |     } | ||
|  |     pthread_attr_destroy(&attr); | ||
|  | } | ||
|  | 
 | ||
|  | /* cmd 是否连接 */ | ||
|  | bool vtycmd_connect(void) | ||
|  | {    | ||
|  |     return vtycmd_ctrl.is_connect; | ||
|  | } | ||
|  | 
 | ||
|  | /* 命令行输出 */ | ||
|  | void vtycmd_print(const char *format, va_list va) | ||
|  | { | ||
|  |     char *buf = vtycmd_ctrl.out_buf + vtycmd_ctrl.out_buf_end; | ||
|  |     char buf_temp[VTY_BUFSIZ]; | ||
|  |     char *buf_temp_p = buf_temp; | ||
|  |     uint16_t start = 0;; | ||
|  |     int len = 0; | ||
|  |     int len_remain = 0; | ||
|  |     int len_temp = 0; | ||
|  | 
 | ||
|  |     if (!vtycmd_ctrl.is_connect) | ||
|  |     { | ||
|  |         vtycmd_ctrl.out_buf_start = 0; | ||
|  |         vtycmd_ctrl.out_buf_end = 0; | ||
|  |         return; | ||
|  |     } | ||
|  | 
 | ||
|  |     len = vsnprintf(buf_temp, VTY_BUFSIZ, format, va); | ||
|  |     if (len <= 0) | ||
|  |     { | ||
|  |         return; | ||
|  |     } | ||
|  | 
 | ||
|  |     /* 计算可写入的数据量 */ | ||
|  |     start = vtycmd_ctrl.out_buf_start; | ||
|  |     if (vtycmd_ctrl.out_buf_end >= start) | ||
|  |     { | ||
|  |         len_remain = VTYCMD_BUF_OUT_LEN - 1 - (vtycmd_ctrl.out_buf_end - start); | ||
|  |     } | ||
|  |     else | ||
|  |     { | ||
|  |         len_remain = start - vtycmd_ctrl.out_buf_end - 1; | ||
|  |     } | ||
|  |     if (len_remain <= 0) | ||
|  |     { | ||
|  |         return; | ||
|  |     } | ||
|  |      | ||
|  |     if (len > len_remain) | ||
|  |     { | ||
|  |         len = len_remain; | ||
|  |     } | ||
|  | 
 | ||
|  |     /* 超过 out_buf 需要分段存储 */ | ||
|  |     if (len + vtycmd_ctrl.out_buf_end > VTYCMD_BUF_OUT_LEN) | ||
|  |     { | ||
|  |         len_temp = VTYCMD_BUF_OUT_LEN - vtycmd_ctrl.out_buf_end; | ||
|  |         memcpy(buf, buf_temp_p, len_temp); | ||
|  |         vtycmd_ctrl.out_buf_end = 0; | ||
|  |         buf = vtycmd_ctrl.out_buf; | ||
|  |         buf_temp_p = buf_temp_p + len_temp; | ||
|  |         len -= len_temp; | ||
|  |          | ||
|  |         memcpy(buf, buf_temp_p, len); | ||
|  |         vtycmd_ctrl.out_buf_end += len; | ||
|  |     } | ||
|  |     else | ||
|  |     { | ||
|  |         memcpy(buf, buf_temp_p, len); | ||
|  |         len_temp = vtycmd_ctrl.out_buf_end + len; | ||
|  |         if (VTYCMD_BUF_OUT_LEN == len_temp) | ||
|  |         { | ||
|  |             vtycmd_ctrl.out_buf_end = 0; | ||
|  |         } | ||
|  |         else | ||
|  |         { | ||
|  |             vtycmd_ctrl.out_buf_end = len_temp; | ||
|  |         } | ||
|  |     } | ||
|  | } | ||
|  | /************************ (C) COPYRIGHT LandPower ***** END OF FILE ****/ |