Repository: ansible/ansible

Issue:
doas become-method hangs forever
When executing commands using the doas become method, the execution seems to hang forever.

``` yaml

---
- hosts: all
  gather_facts: False
  tasks:
    - command: /usr/bin/whoami
      become: True
```

```
% ansible-playbook -i test.inv -vvv --become-method=doas --ask-become-pass test.yml
No config file found; using defaults
DOAS password:
1 plays in test.yml

PLAY ***************************************************************************

TASK [command] *****************************************************************
task path: /home/mf/cm/test/test.yml:5
<hanoi> ESTABLISH SSH CONNECTION FOR USER: None
<hanoi> SSH: EXEC ssh -C -q -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o ControlPath=/home/mf/.ansible/cp/ansible-ssh-%h-%p-%r -tt hanoi ( umask 22 && mkdir -p "$( echo $HOME/.ansible/tmp/ansible-tmp-1449355062.25-183864280109478 )" && echo "$( echo $HOME/.ansible/tmp/ansible-tmp-1449355062.25-183864280109478 )" )
<hanoi> PUT /tmp/tmpylGAdK TO /home/mf/.ansible/tmp/ansible-tmp-1449355062.25-183864280109478/command
<hanoi> SSH: EXEC sftp -b - -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o ControlPath=/home/mf/.ansible/cp/ansible-ssh-%h-%p-%r [hanoi]
<hanoi> ESTABLISH SSH CONNECTION FOR USER: None
<hanoi> SSH: EXEC ssh -C -q -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o ControlPath=/home/mf/.ansible/cp/ansible-ssh-%h-%p-%r -tt hanoi /bin/sh -c 'doas  -u root  echo BECOME-SUCCESS-lelyicqshqztskrukvdaqmskgruxowwj && doas  -u root  env ANSIBLE=true LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8 /usr/local/bin/python2.7 /home/mf/.ansible/tmp/ansible-tmp-1449355062.25-183864280109478/command; rm -rf "/home/mf/.ansible/tmp/ansible-tmp-1449355062.25-183864280109478/" > /dev/null 2>&1'
```

How to debug this the best way?

My `/etc/doas.conf`:

```
permit keepenv { PKG_PATH ENV PS1 SSH_AUTH_SOCK } :wheel
permit nopass keepenv { PKG_PATH ENV PS1 SSH_AUTH_SOCK } root
```

Using ansible 955710267c1992c5e3b5b9eb77f4c76e289e3313



Discussion:
I reproduced, but it only seems to be an issue when passwords are required

so the issue is that we execute doas twice, which prompts for passwords twice, but we only supply one


Resolving patch:
diff --git a/lib/ansible/playbook/play_context.py b/lib/ansible/playbook/play_context.py
--- a/lib/ansible/playbook/play_context.py
+++ b/lib/ansible/playbook/play_context.py
@@ -481,7 +481,7 @@ def detect_su_prompt(data):
                 if self.become_user:
                     flags += ' -u %s ' % self.become_user
 
-                becomecmd = '%s %s echo %s && %s %s env ANSIBLE=true %s' % (exe, flags, success_key, exe, flags, cmd)
+                becomecmd = '%s %s %s -c %s' % (exe, flags, executable, success_cmd)
 
             else:
                 raise AnsibleError("Privilege escalation method not found: %s" % self.become_method)


Test patch:
diff --git a/test/units/playbook/test_play_context.py b/test/units/playbook/test_play_context.py
--- a/test/units/playbook/test_play_context.py
+++ b/test/units/playbook/test_play_context.py
@@ -161,7 +161,7 @@ def test_play_context_make_become_cmd(self):
 
         play_context.become_method = 'doas'
         cmd = play_context.make_become_cmd(cmd=default_cmd, executable="/bin/bash")
-        self.assertEqual(cmd, """%s -c '%s %s echo %s && %s %s env ANSIBLE=true %s'""" % (default_exe, doas_exe, doas_flags, play_context.success_key, doas_exe, doas_flags, default_cmd))
+        self.assertEqual(cmd, """%s -c '%s %s %s -c '"'"'echo %s; %s'"'"''""" % (default_exe, doas_exe, doas_flags, default_exe, play_context.success_key, default_cmd))
 
         play_context.become_method = 'bad'
         self.assertRaises(AnsibleError, play_context.make_become_cmd, cmd=default_cmd, executable="/bin/bash")