SHELL实现跳板机,只允许用户执行少量允许的命令


整理自:http://blog.chinaunix.net/uid-22101889-id-3167454.html

注意:请谨慎使用,到现在为止,还没找到改回去的方法。


两个问题。

第一、很多大公司的服务器都不允许直接登录,而是通过一个跳板机才能登录过去。在跳板机中,通常只能执行几个少数命令(如SSH),而其他命令是不允许执行的,那么怎样才能实现这个功能呢?

第二、一些小公司,由于服务器比较少,不需要什么跳板机之类的说法,公司的开发运维人员加起来也就那么十几二十人,通常大家都知道root密码,所有人都是直接root登录上去,但是有时有人由于失误,把什么服务弄挂了,这时是肯定抓不到人的,因为所有人都知道密码,那么怎样才能知道谁都执行过什么命令呢?或者干脆只让他们执行少数允许的命令呢?


这两个需求,看似不同,其实原理都相同,只要在用户与shell之间加入个检测机制就可以了,您可以去网上找些开源软件,但是如果您嫌那些软件太复杂,又不能完全满足您的需求,那么就完全可以像我这样,自己用shell写一个简易的模拟终端。


在模拟终端里,你需要做的,就是向用户提供一个看起来像是真的但实际不是真的、的虚拟终端。而你需要做的,就是读取用户输入的命令,并在替用户执行之前进行记录,这样就实现了上面第二个需求中的记录功能。如果你不想让用户执行哪些命令,那么仅仅echo一句“Permission denied”就可以将用户阻挡在真正的shell大门之外了。

如果用户要执行的命令是你允许的,那么在执行之前,记录个log就行了。如果将这个虚拟终端设置成只能执行ssh这个命令,那么不就实现了第一个问题中的跳板机的功能了吗。

所以以上两个需求,都可以总结为一个需求,那就是:拦截用户的输入,在用户与shell之间加一道门。

而脚本的功能,就是根据用户不同的输入采取不同的动作。

脚本的长短也就跟需要的命令的多少有关,需要的命令越多,脚本需要判断的就越多,脚本也就越长。

但实际并不需要为每个命令都写一个action,只要为每个种类的写一个action就行了。

比如:最简单的情形,没有任何参数的命令,如:pwd等。
   
稍复杂些的,如touch、ls等命令,这时需要处理参数。

再复杂些的,如rm、mv等命令,不只需要处理参数,还要避免用户误删数据。

而以上所有命令,都需要判断用户是否有权限等等。

脚本的复杂程度,完全取决于你的需求了,下面就贴一个我写的虚拟终端。

在该终端内、实现了用户可以执行cd ls rm mv download upload pwd passwd等等几个命令。

如果您只实现ssh命令,那就是跳板机了。


代码如下:

点击(此处)折叠或打开

  1. # ~/virtual terminal
  2.  
  3. # 将此文件放在/etc/profile.d/目录下,并添加可执行权限。
  4. # 如: -rwxr-xr-x 1 root root 7340 Oct 23 18:12 /etc/profile.d/vt.sh

  5. ############################################################################
  6. # 本行直至文件末尾的代码,用于实现用户登录使用的虚拟终端
  7. # 请勿删除或更改
  8. # 如有疑问、请联系维护负责人: xiaoxi227(QQ451914397)
  9. ############################################################################
  10. # 该文件存放用户名和密码 文件格式为==> 用户名:密码 (每行一个用户)
  11. passwd_file=/etc/user.password 
  12. function red()
  13. {
  14. # 以红色显示
  15. echo -e "\033[31;40m$*\033[0m\n"
  16. }

  17. function green()
  18. {
  19. # 以绿色显示
  20. echo -e "\033[32;40m$*\033[0m\n"
  21. }
  22. # 忽略所有信号,以免用户使用Ctrl+C或者Ctrl+Z等操作退出Virtual Terminal(VT)
  23. for signal in `seq 1 64`
  24. do
  25. trap : $signal &> /dev/null
  26. done
  27. clear
  28. function getchar() # 关闭回显,用于输入密码
  29. {
  30. stty cbreak -echo
  31. dd if=/dev/tty bs=1 count=1 2>/dev/null
  32. stty -cbreak echo
  33. }
  34. ###############################################################################
  35. green "登录成功。" # 用户通过unix pam认证以后显示“登陆成功”,随后进行身份验证
  36. while :
  37. do
  38. read -p "请输入用户名:" username
  39. echo -n "请输入密码: "
  40. while :
  41. do
  42. ret=$(getchar)
  43. if [ x"$ret" = x"" ];then
  44. echo
  45. break
  46. fi
  47. passwd="$passwd$ret"
  48. echo -n '*'
  49. done
  50. correct_passwd=$(gawk -F: "/$username/{ print \$2 }" $passwd_file)
  51. if [ -z "$username" -o -z "$passwd" ];then
  52. clear
  53. red "用户名或密码不能为空"
  54. continue
  55. fi
  56. input_password=$(echo $passwd | md5sum | gawk '{ print $1 }')
  57. if [ x"$input_password" != x"$correct_passwd" ];then
  58. clear
  59. red "用户名或密码错误,请重新输入"
  60. else
  61. break
  62. fi
  63. done
  64. title="
  65. ##################################################################################
  66. ############################## Virtual Terminal ##################################
  67. ##################################################################################
  68. cat | more <<EOF
  69. $title
  70. 使用说明:
  71. 欢迎使用虚拟终端(Virtual Terminal,以下简称VT).
  72. 在此模式下,用户只能执行少量被允许执行的命令,其他命令将会被拒绝执行。
  73. 本模式支持的命令及功能如下:
  74. cd <DIR> 进入<DIR>目录,前提是用户有进入该目录的权限。
  75. ls 功能和系统中的ls命令相同,但是只能显示有读取权限的目录下的文件。
  76. 本命令支持参数,系统中ls命令可以使用的选项都可以在VT模式下使用。
  77. mv <SRC> <DST>  将文件<SRC>移至<DST>,如果路径相同则含义为改名。
  78. 用户必须同时对<SRC>和<DST>有读写权限。
  79. rm <FILE>  将<FILE>从系统中删除。
  80. 当<FILE>是目录时,会递归删除所有子目录及子目录下的文件。
  81. pwd  显示当前的工作路径。
  82. download <FILELIST> 
  83. 将<FILELIST>下载至本机
  84. 运行此命令时,用户使用的终端必须支持ZModem协议,如SecureCRT等。
  85. 下载多个文件需将各文件用空格隔开。
  86. 如果下载的文件是目录,系统会自动将其打包后再下载。
  87. upload  向系统中上传文件,运行此命令后,终端会弹出一个对话框,按提示选择文件上传即可。
  88. 注意:运行此命令时,用户使用的终端必须支持ZModem协议,如SecureCRT等。
  89. passwd  修改自己的登录口令
  90. 如需其他功能,请与管理员联系,VT维护负责人:xiaoxi227(QQ:451914397)
  91. $title
  92. EOF
  93. echo -e "当前登录用户是:\033[32;40m$username\033[0m"
  94. logfile=/var/log/vt.log
  95. function run() # 本函数用于替用户执行命令,并记录log
  96. {
  97. local command="$@"
  98. {
  99. echo -n -e "\033[32;40m$username\033[0m\033[7G -- "
  100. echo -n -e "\033[31;40m`date '+%Y-%m-%d %H:%M:%S'` -- \033[0m$comman d"
  101. echo
  102. } | sed 's/sz/download/g;s/rz/upload/g' >> $logfile
  103. $command
  104. }
  105.  
  106. # 通常开发人员需要部署的程序都在同一目录下,所以为其指定根目录,限定仅在该目录有权限。
  107. ROOT_DIR=/usr # 本例中用/usr目录测试
  108.  
  109. cd $ROOT_DIR # 进入用户的“根目录”

  110. while : # 死循环读取用户输入
  111. do
  112. # 这里的主机名写成“localhost”写死了,您也可以写成$HOSTNAME,这样就会显示主机名了。
  113. read -e -p "[${username}localhost ${PWD##*/}]$ "
  114. # 如上语句模拟产生shell提示符(其实是假的)
  115.  
  116. # 分隔命令和参数
  117. COMMAND=$(echo $REPLY | gawk '{ print $1 }')
  118. OPTION=$(echo $REPLY | sed -r "s/^$COMMAND//g;s/^[[:space:]]+//g")
  119.  
  120. # 判断要执行的命令是什么,根据不同命令设置不同的动作。如下是本例中实现的几个命令:
  121. case $COMMAND in
  122. cd|ls)
  123. # 当执行cd命令且参数为空时,默认cd到根目录,行为要与系统中的cd命令保持一致。
  124. if [ x"$OPTION" = x"" -a x"$COMMAND" = x"cd" ];then
  125. cd $ROOT_DIR
  126. continue
  127. fi
  128. # 判断参数的第一个字符是不是"/",如果不是,说明想要cd或ls的是相对路径。
  129. # 也就是当前目录下的文件活目录,此时用户是有权限的。
  130. first_char=${OPTION:0:1}
  131. if [ x"$first_char" != x"/" ];then
  132. run $REPLY
  133. else
  134. # 如果是绝对路径,那么判断路径是否以$ROOT_DIR开头,若否则提示用户没权限。
  135. echo $OPTION | grep -q ^$ROOT_DIR
  136. if [ $? -eq 0 ];then
  137. run $REPLY
  138. else
  139. echo "$COMMAND: Permission denied." >&2
  140. fi
  141. fi
  142. ;;
  143. # 其他支持的参数:rm、mv、pwd、passwd等等,就不写注释了,自己理解下吧。
  144. rm|mv)
  145. if [ x"$COMMAND" = x"rm" ];then RM='-rf';else RM='';fi
  146. run='ok'
  147. for _file in $OPTION
  148. do
  149. echo $_file | grep -q '-'
  150. [ $? -eq 0 ] && { 
  151. red "本命令在VT模式下不支持参数"; 
  152. continue;
  153. }
  154. echo $_file | grep -q ^$ROOT_DIR
  155. ret=$?
  156. first_char=${_file:0:1}
  157. if [ x"$first_char" = x"/" ];then
  158. if [ $ret -ne 0 ];then
  159. run='not ok'
  160. fi
  161. fi
  162. done
  163. if [ x"$run" = x"ok" ];then
  164. run $COMMAND $RM $OPTION
  165. else
  166. echo "$COMMAND: Permission denied." >&2
  167. fi
  168. ;;
  169. pwd)
  170. run $REPLY
  171. ;;
  172. upload)
  173. run rz
  174. ;;
  175. download)
  176. for _file in $OPTION
  177. do
  178. if [ ! -d $_file ];then
  179. echo "开始下载文件:$_file"
  180. run sz $_file
  181. [ $? -eq 0 ] && green "下载完成" || red "下载失败"
  182. else
  183. echo "${_file}是目录,正在将其打包成${_file}.tar"
  184. tar -cf ${_file}.tar $_file
  185. [ $? -eq 0 ] && green "打包完成,开始下载${_file}.tar" \
  186. || { red "打包失败,无法下载";continue; }
  187. run sz ${_file}.tar
  188. [ $? -eq 0 ] && {
  189. green "下载完成"
  190. echo "正在删除打包文件"
  191. rm -rf ${_file}.tar
  192. [ $? -eq 0 ] && green "删除成功" \
  193. || red "删除失败"
  194. } || red "下载失败"
  195. fi
  196. done
  197. ;;
  198. passwd)
  199. read -e -s -p "请输入旧密码:" old_passwd
  200. echo '******'
  201. old_passwd=$(echo $old_passwd | md5sum | gawk '{ print $1 }')
  202. if [ x"$old_passwd" != x"$correct_passwd" ];then
  203. red "密码输入错误"
  204. continue
  205. else
  206. read -e -s -p "请输入新密码:" new_passwd1
  207. echo '******'
  208. read -e -s -p "请重复新密码:" new_passwd2
  209. echo '******'
  210. if [ x"$new_passwd1" != x"$new_passwd2" ];then
  211. red "两次输入的密码不一致"
  212. continue
  213. else
  214. new_passwd=$(echo $new_passwd1 | md5sum | gawk '{ print $1 }')
  215. sed -i "/$username/s/.*/$username:$new_passwd/g" $passwd_file
  216. fi
  217. fi
  218. ;;
  219. "")
  220. continue
  221. ;;
  222. *)
  223. echo "-bash: $COMMAND: command not found" >&2
  224. ;;
  225. esac
  226. done

执行结果如下:



由于时间仓促,匆匆写完,连语法都没检查,脚本中有些bug没有修复,故本文仅仅提供思想,不保证所有功能都能正常使用。有此需求的朋友可按此方法自己定制脚本。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值