从 Golang 更改 linux 用户密码无效

Changing linux user password from Golang not working

我需要 go 例程中的一行代码来更改 linux 中的用户密码。

从命令行运行的命令:

      echo 'pgc:password' | sudo chpasswd  //"pgc" is the username and "password" 
                                           // is the password I'm changing it to. 

但这在我的 Go 程序中不起作用。我试过用其他单行命令代替,例如: drm file.txt, touch file.txt, 等等

这些都有效。

Go 程序在一个大项目中的一个包中,但我现在只是尝试直接从命令行 运行 它(不是用作函数,而是一个独立的 .go 文件)。

我的代码:

    //I have tried changing back and forth between the package that changesystempassword.go is in 
    // and main, but that has no effect

    package main //one-liners DON'T WORK if package is the package this go file is in

    import (
        "fmt"
        "os/exec"
        //"time"
    )

    func main() {
        err := exec.Command("echo", "'pgc:password'", "|", "sudo", "chpasswd).Run()

        //time.sleep(time.Second) - tried adding a sleep so it would have time?

        if err != nil {
            fmt.Println("Password change unsuccessful"
        } else {
            fmt.Println("Password change successful")
        }
    }

程序为运行(命令行中的./changesystempassword)时的结果是命令行显示“密码更改成功”。但猜猜怎么了。它没有改变。我在网上和 Stack Exchange 上找到了一些类似的示例,但我使用的是我在那里找到的解决方案,但它不起作用。

documentation 表示“使用给定的参数执行指定的程序”。甚至还有一个特定的段落:

Unlike the "system" library call from C and other languages, the os/exec package intentionally does not invoke the system shell and does not expand any glob patterns or handle other expansions, pipelines, or redirections typically done by shells.

因此问题中的代码执行 echo,参数为 'pgc:password'|sudochpasswd。这是成功的,因为 echo 可以完全打印这四个字符串。

解决方案是直接启动chpasswd并写入其标准输入。这是一个最小的例子:

func main() {
    cmd := exec.Command("chpasswd")
    stdin, err := cmd.StdinPipe()
    io.WriteString(stdin, "pgc:password")
}

我建议调整官方 example 中显示的代码,以获得安全代码 error-checking。

您也可以使用 sudo chpasswd 代替 chpasswd。请记住,在这种情况下 sudo 将无法要求输入密码。一种解决方法是在适当的时候使用 NOPASSWD 配置 sudoers。

谢谢赫尔曼。我的误解有点微妙。我花了很长时间试图让你引导我工作的例子。直到一位同事建议我在参数传递给命令后抛出一个 \n,它才终于起作用了。

所以有效的代码(基本上是 Stdin 示例,稍作改动):

cmd := exec.Command("sudo", "chpasswd")
stdin, err := cmd.StdinPipe()
if err != nil {
    log.Fatal(err)
}

go func() {
    defer stdin.Close()
    io.WriteString(stdin, "pgc:password\n")
}()

out, err := cmd.CombinedOutput()
if err != nil {
    log.Fatal(err)
}