我们线上的机器登录都是通过每5秒钟获取一次密码的方式登录的,今天要登录线上的一组机器,发现去不到root的password了,一直显示错误,后通过console进去获取到密码才得以登录进去,因为系统里用的是/usr/bin/mkpasswd的方式来生成密码的,手工执行mkpasswd root, 发现没有返回,也没有报错,打开文件看看源码是怎么写的,发现是一个shell脚本,是通过系统的passwd,/dev/random获取随机数字,和expect来实现每次请求的时候都更改用户的密码并回显到调用的网页上。抄家伙,看看他是哪里出问题了
strace -c -T -f /usr/bin/mkpasswd root
Process 26921 attached
Process 26922 attached (waiting for parent)
Process 26922 resumed (parent 26921 ready)
Process 26923 attached
Process 26923 detached
Process 26922 detached
^CProcess 26921 detached
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
100.00 0.000736 5 141 read
0.00 0.000000 0 4 write
0.00 0.000000 0 136 16 open
0.00 0.000000 0 140 close
0.00 0.000000 0 53 28 stat
0.00 0.000000 0 92 fstat
0.00 0.000000 0 16 lstat
0.00 0.000000 0 9 6 lseek
0.00 0.000000 0 172 mmap
0.00 0.000000 0 84 mprotect
0.00 0.000000 0 34 munmap
0.00 0.000000 0 19 brk
0.00 0.000000 0 100 2 rt_sigaction
0.00 0.000000 0 24 rt_sigprocmask
0.00 0.000000 0 1 rt_sigreturn
0.00 0.000000 0 52 23 ioctl
0.00 0.000000 0 27 17 access
0.00 0.000000 0 3 pipe
0.00 0.000000 0 3 select
0.00 0.000000 0 2 dup2
0.00 0.000000 0 3 getpid
0.00 0.000000 0 7 socket
0.00 0.000000 0 6 6 connect
0.00 0.000000 0 3 clone
0.00 0.000000 0 14 9 execve
0.00 0.000000 0 3 1 wait4
0.00 0.000000 0 3 uname
0.00 0.000000 0 41 1 fcntl
0.00 0.000000 0 2 readlink
0.00 0.000000 0 4 getrlimit
0.00 0.000000 0 14 getuid
0.00 0.000000 0 10 getgid
0.00 0.000000 0 12 geteuid
0.00 0.000000 0 10 getegid
0.00 0.000000 0 2 getppid
0.00 0.000000 0 2 getpgrp
0.00 0.000000 0 1 setsid
0.00 0.000000 0 2 statfs
0.00 0.000000 0 5 arch_prctl
------ ----------- ----------- --------- --------- ----------------
100.00 0.000736 1256 109 total
-c表示打印出统计信息,-T显示没个调用所消耗的时间,-f表示跟着子进程,从上面结果可以看到到了read的地方就一直卡在那里不动,一开始以为是没有读取到用户名,后来代码上加上echo $1,是可以打印出来的,那strace显示是在read的地方卡住的,那问题到底出在哪里了呢,在继续往下看代码,突然想到既然用的expect,那肯定是执行passwd的时候read屏幕回显的字符,代码段在这里
spawn $prog $user
197 expect {
198 "assword*: " {
199 # some systems say "Password (again):"
200 send "$password \r "
201 exp_continue
202 }
203 }
赶紧回shell手工执行以下passwd,发现显示乱码了,echo $LANG,nnd,竟然是zh_CN, 我们线上环境的服务器都是en_US.UTF-8的呀,赶紧加上一条export到.bashrc里面,至此问题解决,就是由于系统语言是中文,导致expect执行的之后无法读取想要匹配的字符导致没法获取到密码。
文章涉及的脚本文件请到这里下载https://github.com/sangrealest/shell/blob/master/mkpasswd