Sophie

Sophie

distrib > Mageia > 6 > armv7hl > media > core-updates-src > by-pkgid > 69bcdf32d5a11501a00d30bea9ca7427 > files > 2

ansible-2.4.6.0-1.3.mga6.src.rpm

From 3465a13824f68b97976b13b00429d83344f93b48 Mon Sep 17 00:00:00 2001
From: Martin Krizek <martin.krizek@gmail.com>
Date: Mon, 22 Oct 2018 17:42:59 +0200
Subject: [PATCH] user: do not pass ssh_key_passphrase on cmdline

CVE-2018-16837

Co-authored-by: Toshio Kuratomi <a.badger@gmail.com>
Modified by Bruno Cornec for Mageia
---
 ...ot-pass-ssh_key_passphrase-on-cmdline.yaml |  2 +
 lib/ansible/modules/system/user.py            | 57 +++++++++++++++++--
 test/integration/targets/user/tasks/main.yml  | 29 ++++++++++
 3 files changed, 83 insertions(+), 5 deletions(-)
 create mode 100644 changelogs/fragments/user-do-not-pass-ssh_key_passphrase-on-cmdline.yaml

diff --git a/changelogs/fragments/user-do-not-pass-ssh_key_passphrase-on-cmdline.yaml b/changelogs/fragments/user-do-not-pass-ssh_key_passphrase-on-cmdline.yaml
new file mode 100644
index 0000000000000..70b4f35a57641
--- /dev/null
+++ b/changelogs/fragments/user-do-not-pass-ssh_key_passphrase-on-cmdline.yaml
@@ -0,0 +1,2 @@
+bugfixes:
+  - user: do not pass ssh_key_passphrase on cmdline (CVE-2018-16837)
diff --git a/lib/ansible/modules/system/user.py b/lib/ansible/modules/system/user.py
index 1bb6b442f71c8..4118f7a452761 100644
--- a/lib/ansible/modules/system/user.py
+++ b/lib/ansible/modules/system/user.py
@@ -248,10 +248,13 @@
 import pwd
 import grp
 import platform
+import pty
+import select
+import subprocess
 import socket
 import time
 import shutil
-from ansible.module_utils._text import to_native
+from ansible.module_utils._text import to_native, to_bytes, to_text
 from ansible.module_utils.basic import load_platform_subclass, AnsibleModule
 from ansible.module_utils.pycompat24 import get_exception
 
@@ -860,13 +862,58 @@ def ssh_key_gen(self):
         cmd.append(self.ssh_comment)
         cmd.append('-f')
         cmd.append(ssh_key_file)
-        cmd.append('-N')
         if self.ssh_passphrase is not None:
-            cmd.append(self.ssh_passphrase)
+            if self.module.check_mode:
+                self.module.debug('In check mode, would have run: "%s"' % cmd)
+                return (0, '', '')
+
+            master_in_fd, slave_in_fd = pty.openpty()
+            master_out_fd, slave_out_fd = pty.openpty()
+            master_err_fd, slave_err_fd = pty.openpty()
+            env = os.environ.copy()
+            env['LC_ALL'] = 'C'
+            try:
+                p = subprocess.Popen([to_bytes(c) for c in cmd],
+                                     stdin=slave_in_fd,
+                                     stdout=slave_out_fd,
+                                     stderr=slave_err_fd,
+                                     preexec_fn=os.setsid,
+                                     env=env)
+                out_buffer = b''
+                err_buffer = b''
+                while p.poll() is None:
+                    r, w, e = select.select([master_out_fd, master_err_fd], [], [], 1)
+                    first_prompt = b'Enter passphrase (empty for no passphrase):'
+                    second_prompt = b'Enter same passphrase again'
+                    prompt = first_prompt
+                    for fd in r:
+                        if fd == master_out_fd:
+                            chunk = os.read(master_out_fd, 10240)
+                            out_buffer += chunk
+                            if prompt in out_buffer:
+                                os.write(master_in_fd, self.ssh_passphrase + b'\r')
+                                prompt = second_prompt
+                        else:
+                            chunk = os.read(master_err_fd, 10240)
+                            err_buffer += chunk
+                            if prompt in err_buffer:
+                                os.write(master_in_fd, self.ssh_passphrase + b'\r')
+                                prompt = second_prompt
+                        if b'Overwrite (y/n)?' in out_buffer or b'Overwrite (y/n)?' in err_buffer:
+                            # This created between us checking for existence and now
+                            return (None, 'Key already exists', '')
+
+                rc = p.returncode
+                out = to_native(out_buffer)
+                err = to_native(err_buffer)
+            except OSError as e:
+                return (1, '', to_native(e))
         else:
+            cmd.append('-N')
             cmd.append('')
 
-        (rc, out, err) = self.execute_command(cmd)
+            (rc, out, err) = self.execute_command(cmd)
+
         if rc == 0 and not self.module.check_mode:
             # If the keys were successfully created, we should be able
             # to tweak ownership.
diff --git a/test/integration/targets/user/tasks/main.yml b/test/integration/targets/user/tasks/main.yml
index 86595a48f47ff..d001cbdc48434 100644
--- a/test/integration/targets/user/tasks/main.yml
+++ b/test/integration/targets/user/tasks/main.yml
@@ -108,3 +108,32 @@
   assert:
       that:
           - '"ansibulluser" not in user_names2.stdout_lines'
+
+
+# Test creating ssh key with passphrase
+- name: Remove ansibulluser
+  user:
+    name: ansibulluser
+    state: absent
+
+- name: Create user with ssh key
+  user:
+    name: ansibulluser
+    state: present
+    generate_ssh_key: yes
+    ssh_key_file: "{{ output_dir }}/test_id_rsa"
+    ssh_key_passphrase: secret_passphrase
+
+- name: Unlock ssh key
+  command: "ssh-keygen -y -f {{ output_dir }}/test_id_rsa -P secret_passphrase"
+  register: result
+
+- name: Check that ssh key was unlocked successfully
+  assert:
+    that:
+      - result.rc == 0
+
+- name: Clean ssh key
+  file:
+    path: "{{ output_dir }}/test_id_rsa"
+    state: absent