-1

I am trying to execute following shell command with Go.

{ echo $password; echo $password; } | kadmin.local -q 'cpw user'

Below changePassword is not allowing me to pipe in both password to kadmin.local utility. I have another utility where I need to pass only one password and this function works fine (if I remove line no:3)

// Update Password
func changePassword(password string, principal string) {
    cmd := exec.Command("kadmin.local", "-q", "cpw "+principal)
    cmd.Stdin = strings.NewReader(password)
    cmd.Stdin = strings.NewReader(password) // Remove when one password require.
    var out bytes.Buffer
    cmd.Stdout = &out
    err := cmd.Run()
    check(err)
    fmt.Println(out.String())
}

I tried other method https://stackoverflow.com/a/10953142/3082827 but I am not able to figure how to make this work.

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
tgcloud
  • 857
  • 6
  • 18
  • 37
  • 2
    `cmd.Stdin = os.Stdin` – Zombo Dec 11 '20 at 06:10
  • @StevenPenny I updated ```cmd.Stdin = os.Stdin``` after second instance of ```cmd.Stdin``` (after line no: 3)but looks like it does not help, it say's ```change_password: Empty passwords are not allowed while changing password``` – tgcloud Dec 11 '20 at 07:18
  • 1
    you cannot consume stdin of the final process with multiple processes in bash (not with the operator used here). You can create multiline input and parse that out. –  Dec 11 '20 at 08:29

2 Answers2

1

The kadmin programs reads passwords directly from the controlling terminal if there is one, not from standard input. This means that setting cmd.Stdin may well have no effect. Fortunately, there is a -pw option: change_password -pw password principal (cpw is short for change_password); unfortunately, use of this option is not secure.

Besides using -pw, then, you have two more options:

  • provide a controlling terminal that is a pseudo-terminal, so that you can provide the password; or
  • make sure there is no controlling terminal, so that kadmin uses stdin.

If you do the latter, the correct thing to send via cmd.Stdin is the password repeated twice, with a newline at the end each time. That is, instead of:

cmd.Stdin = strings.NewReader(password)
cmd.Stdin = strings.NewReader(password)

(which just creates and then throws away one reader instance) you would want:

cmd.Stdin = strings.NewReader(password + "\n" + password + "\n")

or similar.

torek
  • 448,244
  • 59
  • 642
  • 775
  • I have thinking to disable to pseudo-terminal, so I can provide password on stdout. this will require little bit of search. Thanks for valuable info. This sets the direction. :) – tgcloud Dec 11 '20 at 11:52
0

This is working for me. Posting my solution incase someone is stumbling upon.

// Updating Password
func changePassword(password string, principal string) {
    b.Write([]byte(password + "" + password))
    var b bytes.Buffer
    b.Write([]byte(password + "\n" + password + "\n"))
    cmd.Stdin = &b
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr
    err := cmd.Run()
    check(err)
}
tgcloud
  • 857
  • 6
  • 18
  • 37