一下子又是几个月没写呢。总是觉得没东西值得写到blog上,但是又总觉得有代码需要 码。想想还是把这点小东西写一下吧。

最近一台大家共着用的服务器被人误重启了。本来为了防着这种事情发生,我已经很限制 root权限的分发了。但是偏偏那个人用到的脚本非要root来跑(鄙视一下写脚本的人), 没办法,只好给他了root。结果呢,服务器误重启,大概是他手抖了吧。

既然没办法不给root,那么只好想些别的辙来确保服务器的运行。

记录root命令到syslog

这个是为了可以找苦主。以前的服务器上,大家都是root,重启了,谁跑的命令都不知道 ,太糟糕。事后想找个人骂都找不到。

稍稍google了下,在zshrc里面加上了这么一段

zshaddhistory() {
    cmd=${1%%$'\n'}
    print -sr -- $cmd
    LASTCMD="${(pj:\\\n:)${(f)1}}"
    first_arg=${${(z)LASTCMD}[1]}
    ( [[ `id -u $USER` -eq 0 ]] || [[ $first_arg == sudo ]] ) && logger -t "$USER@${TTY/\/dev\/}[$PWD]" $LASTCMD
}

写得很烂,因为我懒。值得注意的是print -sr -- $cmd是输出命令到 ~/.zsh_history而不是屏幕。最后一句很简单,如果执行用户是root,或者命令的第 一个词是sudo,那么就把命令记录到syslog里面去。输出大概是这个样子

Apr  5 06:26:43 bunker root@pts/22[/root]: source .zshrc.local

这只是事后药,而且缺点也很明显,如果用户输入的sudo不在句首,就无法记录了。懒得 管了,咱zsh也就这水准。。。

用alias来防止误重启

好了,怎么防止root用户手一抖就reboot了呢?

失败的方案:

  • 替换/sbin/{reboot,halt,shutdown}:这个太坑人,这些文件不是我们应该碰的。 用包管理装上的文件,除了/etc/底下的,其他都是我不想碰的。

  • 自己写个wrapper脚本,放到路径里面/sbin的前面:先不说脚本的维护,光是路径 里面有同样名字的可执行文件,这就很糟糕了。

我的方案:root用户的zshrc里面加


confirm_yes() {
    sure=$(dialog --stdout  --inputbox "Are you sure that you want to run '$1' command? Type YES to confirm." 10 50)
    [[ $sure == YES ]] && $1
}

for c in reboot halt shutdown; do alias $c="confirm_yes $c"; done

这样用户在输入危险的关机命令的时候,会跳出来一个dialog提示输入大写YES来确认,否 则命令不会被执行。完全不需要另外写wrapper。

参考

http://jablonskis.org/2011/howto-log-bash-history-to-syslog/