Repository: ansible/ansible

Issue:
SUDO passwords with non-ascii characters break Ansible
<!---
Please do not report issues/requests related to Ansible modules here !!

Report them to the appropriate modules-core or modules-extras project:
  - https://github.com/ansible/ansible-modules-core/issues
  - https://github.com/ansible/ansible-modules-extras/issues

Also verify first that your issue/request is not already reported in GitHub
-->
##### ISSUE TYPE

<!--- Pick one below and delete the rest: -->
- Bug Report
##### COMPONENT NAME

<!--- Name of the plugin/task/feature -->

exec_command (local)
##### ANSIBLE VERSION

<!--- Paste verbatim output from “ansible --version” between quotes below -->

```
ansible 2.1.0.0
  config file = /home/USER/git/ansible/ansible.cfg
  configured module search path = Default w/o overrides
```
##### SUMMARY

<!--- Explain the problem briefly -->

We noticed that using a SUDO password with a non-ascii character causes Ansible to throw an exception when feeding the password to sudo. In my case the password include the ° character (0xb0), like the error output indicates:

```
UnicodeEncodeError: 'ascii' codec can't encode character u'\xb0' in position 0: ordinal not in range(128)
```
##### STEPS TO REPRODUCE

<!---
For bugs, show exactly how to reproduce the problem.
For new features, show how the feature would be used.
-->

I intend to write a minimal reproducer an using the master branch.
##### ACTUAL RESULTS

<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->

<!--- Paste verbatim command output between quotes below -->

```
[USER@SYSTEM ansible]$ ansible-playbook some_playbook.yml -K -vvv
Using /home/USER/git/ansible/ansible.cfg as config file
SUDO password:

PLAY [system01] ****************************************************************

TASK [fetch from system] *******************************************************
task path: /home/USER/git/ansible/some_playbook.yml:32
<localhost> ESTABLISH LOCAL CONNECTION FOR USER: USER
<localhost> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /tmp/ansible-tmp-1476453804.28-165187216012413 `" && echo ansible-tmp-1476453804.28-165187216012413="` echo /tmp/ansible-tmp-1476453804.28-165187216012413 `" ) && sleep 0'
<localhost> PUT /tmp/tmpWVAqrj TO /tmp/ansible-tmp-1476453804.28-165187216012413/command
<localhost> EXEC /bin/sh -c 'chown -R sysauto /tmp/ansible-tmp-1476453804.28-165187216012413/ && sleep 0'
<localhost> EXEC /bin/sh -c 'setfacl -R -m u:sysauto:rX /tmp/ansible-tmp-1476453804.28-165187216012413/ && sleep 0'
<localhost> EXEC /bin/sh -c 'sudo -H -S  -p "[sudo via ansible, key=opbxnljylhudewlchnsbwfnibhzyaent] password: " -u sysauto /bin/sh -c '"'"'echo BECOME-SUCCESS-opbxnljylhudewlchnsbwfnibhzyaent; LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8 /usr/bin/python /tmp/ansible-tmp-1476453804.28-165187216012413/command'"'"' && sleep 0'
An exception occurred during task execution. The full traceback is:
Traceback (most recent call last):
  File "/usr/lib/python2.7/site-packages/ansible/executor/task_executor.py", line 124, in run
    res = self._execute()
  File "/usr/lib/python2.7/site-packages/ansible/executor/task_executor.py", line 446, in _execute
    result = self._handler.run(task_vars=variables)
  File "/usr/lib/python2.7/site-packages/ansible/plugins/action/normal.py", line 33, in run
    results = merge_hash(results, self._execute_module(tmp=tmp, task_vars=task_vars))
  File "/usr/lib/python2.7/site-packages/ansible/plugins/action/__init__.py", line 644, in _execute_module
    res = self._low_level_execute_command(cmd, sudoable=sudoable, in_data=in_data)
  File "/usr/lib/python2.7/site-packages/ansible/plugins/action/__init__.py", line 718, in _low_level_execute_command
    rc, stdout, stderr = self._connection.exec_command(cmd, in_data=in_data, sudoable=sudoable)
  File "/usr/lib/python2.7/site-packages/ansible/plugins/connection/local.py", line 109, in exec_command
    p.stdin.write(self._play_context.become_pass + '\n')
UnicodeEncodeError: 'ascii' codec can't encode character u'\xb0' in position 0: ordinal not in range(128)

fatal: [system01]: FAILED! => {"failed": true, "msg": "Unexpected failure during module execution.", "stdout": ""}

NO MORE HOSTS LEFT *************************************************************

PLAY RECAP *********************************************************************
system01                   : ok=0    changed=0    unreachable=0    failed=
```



Discussion:
This seems to be a duplicate of #16557


Resolving patch:
diff --git a/lib/ansible/plugins/connection/local.py b/lib/ansible/plugins/connection/local.py
--- a/lib/ansible/plugins/connection/local.py
+++ b/lib/ansible/plugins/connection/local.py
@@ -106,7 +106,7 @@ def exec_command(self, cmd, in_data=None, sudoable=True):
                     raise AnsibleError('privilege output closed while waiting for password prompt:\n' + become_output)
                 become_output += chunk
             if not self.check_become_success(become_output):
-                p.stdin.write(self._play_context.become_pass + '\n')
+                p.stdin.write(to_bytes(self._play_context.become_pass, errors='surrogate_or_strict') + b'\n')
             fcntl.fcntl(p.stdout, fcntl.F_SETFL, fcntl.fcntl(p.stdout, fcntl.F_GETFL) & ~os.O_NONBLOCK)
             fcntl.fcntl(p.stderr, fcntl.F_SETFL, fcntl.fcntl(p.stderr, fcntl.F_GETFL) & ~os.O_NONBLOCK)
 


Test patch: