Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
FinSH
[新人试水] LPC1768_Nano3_Shell 权限管理
发布于 2018-03-21 21:48:11 浏览:2251
订阅该版
* 本帖最后由 wlof 于 2018-3-21 23:19 编辑 * [align=center]**第三章 Finsh Shell 权限管理** [align=center]Wlof[align=center]摘要:本文介绍了Shell开启密码支持功能的重要设置,并指出了现有代码中的不足之处,并将其稍作修正加以改进,主要是添加了密码输入退格的支持,添加自定义的权限管理,方便用户根据自己的需要使用。为了更好地保护Shell被乱用,提供了只暴露单一入口的示例。 **3.1 起源** Shell这个东西可以方便调试工作,任何事情都有两面性。当我们将一些非常重要的函数,向外提供接口时,我们应该尽可能地保护它,不让非法用户随意乱用。最早有这个想法时,我向群里的高手们请教,问有没有人搞过Shell的用户认证,armink回复Shell本身就支持,OMG,没有仔细看文档,啪啪啪,打脸了... 不过,Shell只是在启动的时候,加入了密码认证,没有看到有注销之类的函数呢?(可能有,只是我没看到,啪啪啪,不要打我,真没看到)于是,想到了大家天天都用的,可以使用输入用户名和密码的方式,来做一个权限管理,然后在执行要保护的操作之前,判断一下权限,每个函数都加上(啪啪啪,又打!别复制,写成函数)。当然,更好的方法是,不要显式的暴露出来,可以提供一个小入口,然后,在它后面搞上一堆参数的方式进行保护,只要对入口施加权限验证就可以了。参数多了记不住,怎么办?windows的命令参数也很多,好像不用记吧?仿过来!(废话又一堆,我比较喜欢先酝酿一下情绪,不然2分钟就弄完了,别人还没明白弄啥子呢) **3.2 打开密码支持功能(自带)** 说在前面,这边出现的东西,Nano自带的config模板里是没有的,要自己手动添加,放心,我试过了,内核里面是支持的。首先打开编程手册,查看文档Finsh Shell章节,看到一堆宏选项(别问我第几页,懒一点的人都知道复制查找,甚至关键字,少复制几个字母都当省力气)。 **#defineFINSH_USING_AUTH ****#defineFINSH_DEFAULT_PASSWORD** "yourpswd"[align=center]![1.jpg](/uploads/201803/21/213528um7ftccholf47ptf.jpg)[align=center]图3-1rtconfig.h中开启认证如果下面那个不定义的话,会使用默认的密码“rtthread”(提示查找“**FINSH_DEFAULT_PASSWORD**”) [align=center]![2.jpg](/uploads/201803/21/214359jx2q0x2ad92e9xep.jpg)[align=center]图3-2默认密码的位置 先看一下效果吧,输入密码变成“*”了,还可以是吧?[align=center]![3.jpg](/uploads/201803/21/213529f4h1qxbmbfnn7c61.jpg)[align=center]图3-3 密码输入变成*号**3.3 添加导出函数(自定义函数)**查一下文档吧,如果不想看的话(我也不太喜欢看,但是一定要结合起来看,这样才能懂得人家在搞什么嘛!查看文档是工程师必备的技能和基本素养,千万不要偷懒。废话又多了,为你好!看这个文章的肯定是新手,所以,要好好读文档,更要注意方法,结合起来读,用到哪读到哪。有句名言叫“步步高点读机,哪里不会点哪里”嘛是不?把那个文档一次从头看到底的,只有两种人,一个高手(文档人家的写的嘛),一个新手(不知道从哪里入手嘛,先浏览一下子呢))。看一下shell上都打印了什么函数,然后,查找,定位到函数定义,它的下面就是导出的关键东东啦! [align=center]![4.jpg](/uploads/201803/21/213529kkjgjn6cctrk767v.jpg)[align=center]图3-4查看都有什么函数 [align=center]![5.jpg](/uploads/201803/21/213529xurr0kxju02wksrw.jpg)[align=center]图3-5查一下list_thread 现在自己写一个函数,打印一行信息,导出来,看一下成不成,效果如图3-6。```/*--------------------------------BEGIN---------------------*/ int logoff(int argc,char** argv) { rt_kprintf("logon off ok!
"); return 0; } MSH_CMD_EXPORT(logoff, exit for the logon user); /*--------------------------------END---------------------*/``` [align=center]![6.jpg](/uploads/201803/21/213529sof8o5ttnv65dq1d.jpg)[align=center]图3-6手动添加导出函数 **3.4 添加密码输入** 那个密码输入是怎么回事呢?我也不知道,怎么办呀?前面不是说过,自带吗?仿真一下,看一下程序跑哪里去,不就知道了?把那个代码复制过来!!!修修改改,搞定! 没有硬件进行仿真的同学,注意了,方法很重要,试一下软仿真行不行?(我也没有试过)不行的话怎么办呢?列活就是没法仿真怎么办呢?“穷则生变”嘛,要学会变通哦,不是说那个宏打开了才能有那个功能吗?那咱就找一下那个宏都在哪个地方用了,这基本上能定位个大概。 [align=center]![7.jpg](/uploads/201803/21/213530tgg3nwugpufatu7t.jpg)[align=center]图3-7查找“FINSH_USING_AUTH” 加几个断点仿真一下,看一下跑哪去了?发现,打完RT的版权信息后,进入了437行,加载密码嘛,然后进入445行,如图3-8。 [align=center]![8.jpg](/uploads/201803/21/213530hxfpxq4jjztf8pe4.jpg)[align=center]图3-8代码运行到finsh_wait_authfinsh_wait_auth这个函数,再跑,发现没有出来,好了,我们找到了,就是这个函数,进去看一下。 [align=center]![9.jpg](/uploads/201803/21/214408w8mng6q9h2q8hg6h.jpg) [align=center]图3-9密码输入提示原来卡在这里面呢,一直读输入字符呢!那么,密码显示肯定也在这里了! [align=center]![10.jpg](/uploads/201803/21/214400lb8rhw8a8wdwihh8.jpg)[align=center]图3-10密码输入关键代码 为什么会是这个样子的呢?你可以打开putty,断开串口,然后输入字符试一下,屏上没有打印任何信息出来,说明这里的显示要求串口回发,发回来什么就显示什么,我们要保护密码,那就写入一个“*”!这样就够了吗?肉肉肉!在测试时,发现密码输错时,没有办法删除!真是蛋疼!来,修正它,怎么办?把那个码加进来判断一下就是了,不知道是什么值,仿真一下就知道了!``` else if(ch == 0x7f || ch == 0x08) { if(cur_pos != 0) { cur_pos--; password[cur_pos] = 0; rt_kprintf("\b \b"); } } ``` [align=center]![11.jpg](/uploads/201803/21/214400o1n8rywrorz13oyl.jpg)[align=center]图3-11添加密码删除 这样做还不够,有几个特别的键,很让人讨厌,那就是方向键,一连发好几个码过来,怎么办?同样处理,屏蔽它们,如图3-12。``` ``````{ if (ch == 0x1b) { shell->stat = WAIT_SPEC_KEY; continue; } else if (shell->stat == WAIT_SPEC_KEY) { if (ch == 0x5b) { shell->stat = WAIT_FUNC_KEY; continue; } shell->stat = WAIT_NORMAL; } else if (shell->stat == WAIT_FUNC_KEY) { shell->stat = WAIT_NORMAL; continue; } } //---------------这个代码也是直接参考过来的,shell.c 461行 ``` 至此密码,输入函数写好了,【我们修正了一个小BUG哦,爽不爽?】 ```//-----------------用于密码输入--------------- static__inline int read_inputdat(rt_uint8_t *password) { char ch; rt_bool_t input_finish = RT_FALSE; rt_size_t cur_pos = 0; while (!input_finish) { /* wait receive */ if (rt_sem_take(&shell->rx_sem, RT_WAITING_FOREVER) != RT_EOK) continue; /* read one character from device */ while (rt_device_read(shell->device, 0, &ch, 1) == 1) { { //--------------------过滤 上 下 左 右 /* * handle control key * up key : 0x1b 0x5b 0x41 * down key: 0x1b 0x5b 0x42 * right key:0x1b 0x5b 0x43 * left key: 0x1b 0x5b 0x44 */ if (ch == 0x1b) { shell->stat = WAIT_SPEC_KEY; continue; } else if (shell->stat == WAIT_SPEC_KEY) { if (ch == 0x5b) { shell->stat = WAIT_FUNC_KEY; continue; } shell->stat = WAIT_NORMAL; } else if (shell->stat == WAIT_FUNC_KEY) { shell->stat = WAIT_NORMAL; continue; } }//--------------------过滤 上 下 左 右 // //---------------------读取有效字符 if (ch >= ' ' && ch <= '~' && cur_pos < RT_USER_PWD_SIZE) { /* change the printable characters to'*' */ rt_kprintf("*"); password[cur_pos++] = ch; } else if(ch == 0x7f || ch == 0x08) //修正密码输入无法删除的错误 { if(cur_pos != 0) { cur_pos--; password[cur_pos] = 0; //注意,之前写入的值要清0 rt_kprintf("\b \b"); //屏幕显示清除 } } else if (ch == ' ' || ch == '
') { rt_kprintf("
"); input_finish = RT_TRUE; break; } else if (cur_pos >= RT_USER_PWD_SIZE ) { rt_kprintf("
[error]---->inputis more than 16 byte!
"); input_finish = RT_TRUE; break; } } } return 0; } // static__inline void rt_input_username(void) { //--------------------------------------------username rt_kprintf("please inputthe username:"); rt_memset(rt_inputwd,0,sizeof(rt_inputwd)); read_inputdat(rt_inputwd); } // static__inline void rt_input_password(void) { rt_kprintf("please inputthe password:"); rt_memset(rt_inputwd,0,sizeof(rt_inputwd)); read_inputdat(rt_inputwd); } //``` 至此,调用rt_input_username和rt_input_password就可以实现密码输入了。提示一下,头上加个extern struct finsh_shell *shell;后面会上传工程,到里面去看吧。 **3.5 添加权限管理**权限管理,简单地说,输入用户名和密码都对了,给它设置一个标志。为了更好地实现操作权限控制,不同的用户,标志是不一样的,这样就可以实现分组了。 这里实质上就是对字符串进行对比,没有什么好说了,对比完后,给变量一个值。具体看代码吧。 **3.6 函数入口添加权限控制**在函数入口处,对权限标志进行判断,权限过低的,直接退出去就可以实现保护了。 **3.7 函数入口都不让看**思路:提供一个函数入口,以参数的形式调用真实的函数,不将入口直接显示出来,通过帮助文件的方式为管理员提供命令提示。 [align=center]![12.jpg](/uploads/201803/21/213530j1cckkdtkvk1dpwv.jpg)[align=center]图3-12运行效果具体的参看代码。 **3.8 环境提示**MDK 5以上,LPC17xx包,Nano 3.0.3 文档下载:![RT_Nano_V3初级教程_3 Shell权限管理.pdf](/uploads/201803/21/213746adx83ygee1xece83.attach) 代码下载:![CRSytem_RTT3_share_3.rar](/uploads/201803/21/213914qpkfklfwzl7fhifp.rar) ----------------------------下期:开启LPC1768上的I2C,把用户和密码放到EEPROM中去
查看更多
5
个回答
默认排序
按发布时间排序
armink
2018-03-21
这家伙很懒,什么也没写!
赞赞赞~~~ 楼主费心了,文档整理的也很好!
armink
2018-03-21
这家伙很懒,什么也没写!
``` 就是下次记得贴代码的时候注意下格式,编辑器里有贴代码标签 ```
wlof
2018-03-21
这个家伙不懒,什么也没写
> --- 好的,我修改一下
wlof
2018-03-27
这个家伙不懒,什么也没写
对输入函数进行了修正,屏蔽功能键。 ``` //-----------------用于密码输入--------------- static__inline int read_inputdat(rt_uint8_t *password) { char ch; rt_bool_t input_finish = RT_FALSE; rt_size_t cur_pos = 0; while (!input_finish) { /* wait receive */ if (rt_sem_take(&shell->rx_sem, RT_WAITING_FOREVER) != RT_EOK) continue; /* read one character from device */ while (rt_device_read(shell->device, 0, &ch, 1) == 1) { { //--------------------过滤 上 下 左 右 /* * handle control key * up key : 0x1b 0x5b 0x41 * down key: 0x1b 0x5b 0x42 * right key:0x1b 0x5b 0x43 * left key: 0x1b 0x5b 0x44 */ if (ch == 0x1b) { shell->stat = WAIT_SPEC_KEY; continue; } else if (shell->stat == WAIT_SPEC_KEY) { if (ch == 0x5b) { shell->stat = WAIT_FUNC_KEY; continue; } shell->stat = WAIT_NORMAL; } else if (shell->stat == WAIT_FUNC_KEY) { /*--------------------------2018.03.27-------------------------*/ //Home Insert End Delete PgUp PgDn这6个键会发送4个码过来,所以要对它们进行屏蔽,最后一字节为0x7e(~) //不屏蔽会出问题哦 if((ch < 0x31)||(ch >0x36)) { shell->stat = WAIT_NORMAL; } continue; } }//--------------------过滤 上 下 左 右 // //---------------------读取有效字符 if (ch >= ' ' && ch <= '~' && cur_pos < RT_USER_PWD_SIZE) { /* change the printable characters to'*' */ rt_kprintf("*"); password[cur_pos++] = ch; } else if(ch == 0x7f || ch == 0x08) //修正密码输入无法删除的错误 { if(cur_pos != 0) { cur_pos--; password[cur_pos] = 0; //注意,之前写入的值要清0 rt_kprintf("\b \b"); //屏幕显示清除 } } else if (ch == '\r' || ch == '\n') { rt_kprintf("\n"); input_finish = RT_TRUE; break; } else if (cur_pos >= RT_USER_PWD_SIZE ) { rt_kprintf("\n[error]---->inputis more than 16 byte!\n"); input_finish = RT_TRUE; break; } } } return 0; } ```
armink
2018-03-27
这家伙很懒,什么也没写!
赞,楼主考虑的更完善了~~ 其实 RTT 作为嵌入式 OS ,本身对也是资源比较敏感的。一些可能功能用的非常少,同时实现代码过多,所以也就暂时没去做。 建议楼主也可以更多的关注下常用功能的用户体验,完善了这些代码,产生的价值会大很多。
撰写答案
登录
注册新账号
关注者
0
被浏览
2.3k
关于作者
wlof
这个家伙不懒,什么也没写
提问
24
回答
64
被采纳
0
关注TA
发私信
相关问题
1
RT-THREAD shell无反应呢?
2
RT-thread2.0beta下用类似linux风格MSH,参数如何输入和导出
3
rt-thread finsh windows下的那个终端软件叫什么来着
4
板子上只有485接口,能把FINSH改造成485的么?
5
finsh最大字符问题
6
finsh命令个数是不是有限制啊
7
finsh支持转义字符吗
8
不用finsh如何知道堆栈使用量
9
强烈建议 RT-Thread下finsh原理深入分析
10
finsh输入命令全部返回null node
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
最新文章
1
rt-thread使用cherryusb实现虚拟串口
2
《C++20 图形界面程序:速度与渲染效率的双重优化秘籍》
3
《原子操作:程序世界里的“最小魔法单位”解析》
4
《C++设计模式:重塑游戏角色系统类结构的秘籍》
5
rt-thread官方usb驱动之虚拟串口
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
ART-Pi
FinSH
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
ota在线升级
UART
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
rt_mq_消息队列_msg_queue
keil_MDK
at_device
ulog
C++_cpp
本月问答贡献
踩姑娘的小蘑菇
6
个答案
3
次被采纳
张世争
8
个答案
2
次被采纳
rv666
5
个答案
2
次被采纳
用户名由3_15位
11
个答案
1
次被采纳
KunYi
6
个答案
1
次被采纳
本月文章贡献
出出啊
1
篇文章
2
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
1
次点赞
crystal266
2
篇文章
2
次点赞
whj467467222
2
篇文章
1
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部