【问题标题】:Using the passwd command from within a shell script在 shell 脚本中使用 passwd 命令
【发布时间】:2009-04-03 17:34:53
【问题描述】:

我正在编写一个 shell 脚本来自动添加一个新用户并更新他们的密码。我不知道如何让 passwd 从 shell 脚本中读取,而不是交互式地提示我输入新密码。我的代码如下。

添加用户 $1
密码 $1
2美元
$2

【问题讨论】:

标签: linux bash unix shell


【解决方案1】:

来自“man 1 passwd”:

   --stdin
          This option is used to indicate that passwd should read the new
          password from standard input, which can be a pipe.

所以你的情况

adduser "$1"
echo "$2" | passwd "$1" --stdin

[更新] cmets 中提出了一些问题:

您的passwd 命令可能没有--stdin 选项:使用chpasswd 正如ashawley 所建议的那样,使用实用程序。

如果您使用 bash 以外的 shell,“echo”可能不是内置命令, shell 将调用/bin/echo。这是不安全的,因为密码 将显示在进程表中,并且可以使用ps 等工具查看。

在这种情况下,您应该使用另一种脚本语言。这是 Perl 中的一个示例:

#!/usr/bin/perl -w
open my $pipe, '|chpasswd' or die "can't open pipe: $!";
print {$pipe} "$username:$password";
close $pipe

【讨论】:

  • 你应该引用你的参数扩展。而且;这绝不是便携的形状或形式,甚至丝毫不推荐。有关该主题的更多信息,请参阅我的回复。
  • 请不要使用 echo ... |密码!然后,运行 ps 的任何其他用户都可以看到密码。而且你传递密码的地方越多(不同的程序、文件、管道等),它泄露到某个地方的可能性就越大。
  • @lhunath:你的引用是对的,我会解决的。 @Brian:“echo”是 bash 内置的,它不会显示在 'ps' 输出中(至少在 bash 中,不确定 sh)
  • 如果 bash 则 passwd "$1" <<< "$2"
  • @glennjackman 请注意这里的字符串隐含地创建了可以被外部源读取的临时文件。
【解决方案2】:

唯一的解决方案适用于 Ubuntu 12.04:

echo -e "new_password\nnew_password" | (passwd user)

但第二个选项仅在我更改时才有效:

echo "password:name" | chpasswd

收件人:

echo "user:password" | chpasswd

请参阅原帖中的解释:Changing password via a script

【讨论】:

  • echo 'user:newpassword' | sudo chpasswd,或者没有 sudo 作为 root。
  • 如果密码在第一种情况下包含“\n”怎么办?有办法处理这个吗?如my@secret\npasword123
  • 与第一个类似但自动重复密码。另外,使用 sudo 否则它会首先询问当前密码并将其搞砸。 echo password | sed 's/.*/\0\n\0/' | sudo passwd -q $USER 2> /dev/null
【解决方案3】:

现在,你可以使用这个命令:

echo "user:pass" | chpasswd

【讨论】:

  • 由于某种原因,我在尝试您的命令时收到以下错误:“身份验证令牌操作错误”。在 chpasswd 之前添加 sudo 为我解决了这个问题。
  • @LaurentVanWinckel - chpasswd 仅适用于 sudo/root 权限。因此,要以root 以外的用户身份执行它,该用户必须在sudo 组中:echo 'user:pass' | sudo chpasswd。在提示符下执行此单行代码时,请确保在其前面加上一个空格。否则,包含敏感密码的命令可能会被写入用户的提示历史文件,例如~/.bash_history.
【解决方案4】:

从以下内容中读到明智的话:

我引用:

你可以在 bash 中做的任何事情都不可能奏效。 passwd(1) 不从标准输入读取。这是故意的。这是为了保护你。密码从未打算放入程序或由程序生成。它们只能由具有功能性大脑的真实人类的手指输入,并且永远不会在任何地方写下来。

尽管如此,我们还是有大量用户询问他们如何才能绕过 35 年的 Unix 安全。

它继续解释如何正确设置shadow(5) 密码,并向您展示 GNU-I-only-care-about-security-if-it-doesn't-make-me-想太多-滥用passwd(1)的方式。

最后,如果你打算使用愚蠢的 GNU passwd(1) 扩展 --stdin,不要在命令行中传递密码。

echo $mypassword | passwd --stdin # Eternal Sin.
echo "$mypassword" | passwd --stdin # Eternal Sin, but at least you remembered to quote your PE.
passwd --stdin <<< "$mypassword" # A little less insecure, still pretty insecure, though.
passwd --stdin < "passwordfile" # With a password file that was created with a secure `umask(1)`, a little bit secure.

最后一个是你可以用 GNU passwd 做的最好的事情。虽然我仍然不会推荐它。

在命令行上输入密码意味着任何人即使是最遥远的进入盒子的提示也可以监视ps或类似的东西并窃取密码。即使你认为你的盒子是安全的;这是你应该真正养成不惜一切代价避免的事情(是的,即使是为了完成工作而付出更多麻烦的代价)。

【讨论】:

  • 请问为什么这“仍然很不安全”? $ passwd --stdin
  • @JackTang 您的参数扩展需要引号。
【解决方案5】:

对于那些需要通过脚本登录到 sudoers 文件中的用户帐户远程“以 root 身份运行”的人,我发现了一个邪恶的可怕黑客,这无疑是非常不安全的:

sshpass -p 'userpass' ssh -T -p port user@server << EOSSH
sudo -S su - << RROOT
userpass
echo ""
echo "*** Got Root ***"
echo ""
#[root commands go here]
useradd -m newuser
echo "newuser:newpass" | chpasswd
RROOT
EOSSH

【讨论】:

    【解决方案6】:
    如果您的passwd 不支持--stdin 并且您出于某种原因不想(或不能)使用chpasswd,

    Here-document 有效。

    示例:

    #!/usr/bin/env bash
    
    username="user"
    password="pass"
    
    passwd ${username} << EOD
    ${password}
    ${password}
    EOD
    

    在 Arch Linux 下测试。这个passwd 是shadow-utils 的一个元素,是从core/filesystem 包中安装的,因为core/base 需要这个包,所以您通常会默认拥有该包。

    【讨论】:

      【解决方案7】:

      在我为这类事情保留的 CentOS VMWare 映像上对此进行了测试。请注意,您可能希望避免将密码作为命令行参数,因为整个机器上的任何人都可以从 'ps -ef' 中读取它们。

      也就是说,这将起作用:

      user="$1"
      password="$2"
      adduser $user
      echo $password | passwd --stdin $user
      

      【讨论】:

        【解决方案8】:

        你可以使用 chpasswd

        echo $1:$2 | chpasswd

        【讨论】:

          【解决方案9】:

          您是否查看过adduser 的-p 选项(AFAIK 只是useradd 的另一个名称)?您可能还想查看luseradd 的-P 选项,它采用明文密码,但我不知道luseradd 是否是标准命令(它可能是SE Linux 的一部分,也可能只是一个奇怪的Fedora)。

          【讨论】:

            【解决方案10】:

            有时设置一个没人知道的密码很有用。这似乎有效:

            tr -dc A-Za-z0-9 < /dev/urandom | head -c44 | passwd --stdin $user
            

            【讨论】:

            • 最好禁用一个帐户/禁用它的登录,而不是给它一个未知的密码但让它的登录保持活跃。
            • 密码 --delete 或 --lock
            【解决方案11】:

            这是 teradata 节点管理员的明确答案。

            转到您的 /etc/hosts 文件并在文本文件中创建 IP 或节点名称列表。

            SMP007-1
            SMP007-2
            SMP007-3
            

            将以下脚本放入文件中。

            #set a password across all nodes
            printf "User ID: "
            read MYUSERID
            printf "New Password: "
            read MYPASS
            
            while read -r i; do
                echo changing password on "$i"
                ssh root@"$i" sudo echo "$MYUSERID":"$MYPASS" | chpasswd
                echo password changed on "$i"
            done< /usr/bin/setpwd.srvrs
            

            好的,我知道我已经使用 ssh 和 root 破坏了基本安全规则 但我会让你的安全人员处理它。

            现在把它和​​setpwd.srvrs 配置文件一起放在你的/usr/bin 子目录中。

            当您运行该命令时,它会提示您一次输入用户 ID 然后一次输入密码。然后脚本遍历所有节点 在setpwd.srvrs 文件中,对每个节点执行无密码 ssh, 然后在没有任何用户交互或辅助的情况下设置密码 密码验证。

            【讨论】:

            • 我修复了其中最严重的错误,但这根本不是最佳实践。在 /usr/bin 中硬编码本地数据文件只是一个可怕的想法。
            【解决方案12】:

            我偶然发现了同样的问题,由于某种原因,--stdin 选项在我使用的 passwd 版本上不可用(在 Ubuntu 14.04 中提供)。

            如果你们中的任何人碰巧遇到同样的问题,您可以像我一样使用chpasswd 命令来解决它,如下所示:

            echo "<user>:<password>" | chpasswd
            

            【讨论】:

              【解决方案13】:

              对我来说,在 Raspbian 上它只能以这种方式工作(添加了旧密码):

              #!/usr/bin/env bash
              
              username="pi"
              password="Szevasz123"
              new_ps="Szevasz1234"
              
              passwd ${username} << EOD
              ${password}
              ${new_ps}
              ${new_ps}
              EOD
              

              【讨论】:

                【解决方案14】:

                echo '你的密码' | sudo -S yourCommand

                如果 -S 不起作用,请尝试使用 -kS

                【讨论】:

                  【解决方案15】:

                  您可以使用the expect utility 来驱动从 tty 读取的所有程序(与 stdin 不同,这是 passwd 所做的)。 Expect 附带了针对各种交互问题的可运行示例,例如 passwd 输入。

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2017-12-08
                    • 2016-12-10
                    • 2016-10-01
                    • 2021-08-13
                    • 2017-10-24
                    相关资源
                    最近更新 更多