期望不会将输入传递给bash脚本中的passwd

问题描述:

我试图使用expect将$ PASSWORD变量内容传递给passwd。这似乎工作,添加用户,但一旦你尝试通过ssh登录与其中一个用户,它不起作用。如果我手动设置密码,那就好了。期望不会将输入传递给bash脚本中的passwd

有没有人遇到过这个问题?

USERS=(user1 user2 user3) 



generatePassword() 
{ 
     pwgen 16 -N 1 
} 

# Check if user is root 
if [ $(whoami) != 'root' ]; then 
     echo "Must be root to run $0" 
     exit 1; 
fi 

# Check if pwgen is installed: 
if [[ $(dpkg -s pwgen > /dev/null 2>&1; echo ${PIPESTATUS}) != '0' ]]; then 
     echo -e "pwgen is not installed, this script will not work without it\n\n'apt-get install pwgen'\n" 
     exit 1; 
    else 
     echo -e "Starting Script...\n\n" 
fi 

# Iterate through users and add them with a password 
for i in ${USERS[@]}; do 
     PASSWORD=$(generatePassword) 
     echo "$i $PASSWORD" >> passwords 

     useradd -m "${i}" 

     echo -e "Adding $i with a password of '$PASSWORD'\n" 

     expect -c " 
      spawn passwd ${i} 

      expect \"Enter new UNIX password:\" 
      send -- \"$PASSWORD\r\" 
      send -- \"\r\" 
      expect \"Retype new UNIX password:\" 
      send -- \"$PASSWORD\r\" 
      send -- \"\r\" 
      " 
      echo -e "\nADDED $i with a password of '$PASSWORD'\n" 
done 
+0

Ewww。你正在对你打算作为代码解析的内容进行字符串替换?这是一个重要的代码异味 - 如果用户被允许设置自己的密码,这可能被用作任意指令注入漏洞。 –

+0

顺便说一句,请参阅http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html了解有关环境变量名称的POSIX约定(以及因此共享一个命名空间的shell变量的名称) - 全部大写的名称是由具有含义的变量用于shell或操作系统,至少包含一个小写字符的名称被保留供应用程序使用;因此,考虑使用'password'而不是'PASSWORD'来避免错误地覆盖一个有意义的变量。 –

+0

@CharlesDuffy - 我知道,这是一小时摸索无知的结果!我试图变得更好 – Detnon

您续需要期望在所有:使用chpasswd代替passwd

#!/bin/bash 
users=(user1 user2 user3) 

# Check if user is root 
if [[ "$(id -un)" != 'root' ]]; then 
    echo "Must be root to run $0" 
    exit 1 
fi 

# Check if pwgen is installed: 
if ! dpkg -s pwgen > /dev/null 2>&1; then 
    printf "pwgen is not installed, this script will not work without it\n\n'apt-get install pwgen'\n" 
    exit 1 
else 
    printf "Starting Script...\n\n" 
fi 

# Iterate through users and create a password 
passwords=() 
for user in "${users[@]}"; do 
    useradd -m "$user" 
    password="$user:$(pwgen 16 -N 1)" 
    passwords+=("$password") 
    echo "Adding user '$user' with '$password'" 
done 

printf "%s\n" "${passwords[@]}" | chpasswd 

我已经添加了这些需要几个引号。
我简化了dpkg检查。

或者,也许更简单,newusers自动执行“useradd”和“passwd”函数。

for user in "${users[@]}"; do 
    password="$user:$(pwgen 16 -N 1)" 
    password=${password//:/-}   # replace all colon with hyphen 
    printf "%s:%s::::/home/%s:/bin/bash\n" "$user" "${password//:/-}" "$user" 
done | newusers 

我不认为newusers从/ etc/skel中填充home目录。

第一:最紧迫的问题是,你是不是逃避反斜杠文字,当你键入\r,所以这些都只是变成r S于该expect侧;看来解决问题的最小可能变化是将其更改为\\r


但是 - 不要这样做的:在expect与其他语言,字符串可以作为文字传递,没有代入代码。

expect -f <(printf '%s\n' ' 
set username [lindex $argv 0]; 
set password [lindex $argv 1]; 
spawn passwd $username 

expect "Enter new UNIX password:" 
send -- "$password\r" 
send -- "\r" 
expect "Retype new UNIX password:" 
send -- "$password\r" 
send -- "\r" 
') -- "$i" "$PASSWORD" 

你也可以有问题的文字文本保存到一个文件,并运行expect -f passwd.expect -- "$i" "$PASSWORD",这将很好的工作(并避免对<()语法,这是庆典采用了KSH扩展的依赖)。

+0

我可能会以Un _expect_ ed方式使用Expect ... 我是否正确假设我需要[lindex $ argv 0]部分?我认为这是需要的,如果我在我的脚本的开头使用参数? – Detnon

+0

所以,re:'[lindex $ argv 0]'部分,这样做是将变量从命令行拖到awk中。 (在'--'后面的末尾,我们将shell变量放在awk命令行后面;'set username'和'set password'是我们获取这些命令行参数并创建awk变量的地方)。 –

+0

这样做而不是直接将值代入awk脚本的目的是通过令人惊讶或恶意的用户名或密码来避免注入攻击。请参阅https://xkcd.com/327/以快速介绍可防止此类攻击的SQL等效项;保持数据不被注入代码的最好方法是*从代码*中带外传输数据,这是在这里执行的。 –