2.7: user: do not pass ssh_key_passphrase on cmdline (#47445)

* user: do not pass ssh_key_passphrase on cmdline

CVE-2018-16837

Co-authored-by: Toshio Kuratomi <a.badger@gmail.com>
(cherry picked from commit a0aa53d1a1)

* Ignore user module use of subprocess.

(cherry picked from commit 8d00afc013)

* Fix python3 problem in user module cve fix

(cherry picked from commit 9088671c4e)

* Fix changelog entry for user module CVE fix

(cherry picked from commit 210a43ebeb)
This commit is contained in:
Martin Krizek 2018-10-23 04:59:34 +02:00 committed by Toshio Kuratomi
parent b14c45a16c
commit b618339c32
4 changed files with 84 additions and 5 deletions

View file

@ -0,0 +1,2 @@
bugfixes:
- user module - do not pass ssh_key_passphrase on cmdline (CVE-2018-16837)

View file

@ -355,13 +355,15 @@ import grp
import os
import re
import platform
import pty
import pwd
import select
import shutil
import socket
import subprocess
import time
import re
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
try:
@ -860,13 +862,58 @@ class User(object):
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, to_bytes(self.ssh_passphrase, errors='strict') + 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, to_bytes(self.ssh_passphrase, errors='strict') + b'\r')
prompt = second_prompt
if b'Overwrite (y/n)?' in out_buffer or b'Overwrite (y/n)?' in err_buffer:
# The key was 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)
if rc == 0 and not self.module.check_mode:
# If the keys were successfully created, we should be able
# to tweak ownership.

View file

@ -493,3 +493,32 @@
- result.bakup
- shadow_backups.files | map(attribute='path') | list | length > 0
when: ansible_os_family == 'Solaris'
# 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

View file

@ -1141,6 +1141,7 @@ lib/ansible/modules/system/svc.py E322
lib/ansible/modules/system/svc.py E324
lib/ansible/modules/system/ufw.py E322
lib/ansible/modules/system/ufw.py E326
lib/ansible/modules/system/user.py E210
lib/ansible/modules/system/user.py E324
lib/ansible/modules/system/user.py E327
lib/ansible/modules/system/vdo.py E324