Accepting request 846425 from systemsmanagement:saltstack
- Set passphrase for salt-ssh keys to empty string (bsc#1178485) - Added: * set-passphrase-for-salt-ssh-keys-to-empty-string-293.patch - Properly validate eauth credentials and tokens on SSH calls made by Salt API (bsc#1178319) (bsc#1178362) (bsc#1178361) (CVE-2020-25592) (CVE-2020-17490) (CVE-2020-16846) - Added: * fix-cve-2020-25592-and-add-tests-bsc-1178319.patch - Fix novendorchange handling in zypperpkg module - Added: * fix-novendorchange-option-284.patch - Fix disk.blkid to avoid unexpected keyword argument '__pub_user' (bsc#1177867) - Added: * path-replace-functools.wraps-with-six.wraps-bsc-1177.patch OBS-URL: https://build.opensuse.org/request/show/846425 OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/salt?expand=0&rev=111
This commit is contained in:
commit
9cc348312b
@ -1 +1 @@
|
|||||||
3ce95a1b386927b6f8cb27d1a6421018bebccd9a
|
24bd64b440c2c3f0f154a1b7f7216de20dc07df8
|
581
fix-cve-2020-25592-and-add-tests-bsc-1178319.patch
Normal file
581
fix-cve-2020-25592-and-add-tests-bsc-1178319.patch
Normal file
@ -0,0 +1,581 @@
|
|||||||
|
From e7514afcba4f57c5cb8599f561fcefdcc3db7314 Mon Sep 17 00:00:00 2001
|
||||||
|
From: "Daniel A. Wozniak" <dwozniak@saltstack.com>
|
||||||
|
Date: Wed, 16 Sep 2020 00:25:10 +0000
|
||||||
|
Subject: [PATCH] Fix CVE-2020-25592 and add tests (bsc#1178319)
|
||||||
|
|
||||||
|
Properly validate eauth credentials and tokens on SSH calls made by Salt API
|
||||||
|
|
||||||
|
(bsc#1178319) (bsc#1178362) (bsc#1178361) (CVE-2020-25592) (CVE-2020-17490) (CVE-2020-16846)
|
||||||
|
---
|
||||||
|
salt/client/ssh/shell.py | 26 ++-
|
||||||
|
salt/modules/tls.py | 18 +-
|
||||||
|
salt/netapi/__init__.py | 67 ++++++
|
||||||
|
tests/integration/netapi/test_client.py | 296 +++++++++++++++++++++++-
|
||||||
|
4 files changed, 388 insertions(+), 19 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/salt/client/ssh/shell.py b/salt/client/ssh/shell.py
|
||||||
|
index bd55c514ee..27aba7b382 100644
|
||||||
|
--- a/salt/client/ssh/shell.py
|
||||||
|
+++ b/salt/client/ssh/shell.py
|
||||||
|
@@ -8,6 +8,7 @@ from __future__ import absolute_import, print_function, unicode_literals
|
||||||
|
import re
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
+import shlex
|
||||||
|
import time
|
||||||
|
import logging
|
||||||
|
import subprocess
|
||||||
|
@@ -43,10 +44,10 @@ def gen_key(path):
|
||||||
|
'''
|
||||||
|
Generate a key for use with salt-ssh
|
||||||
|
'''
|
||||||
|
- cmd = 'ssh-keygen -P "" -f {0} -t rsa -q'.format(path)
|
||||||
|
+ cmd = ["ssh-keygen", "-P", '""', "-f", path, "-t", "rsa", "-q"]
|
||||||
|
if not os.path.isdir(os.path.dirname(path)):
|
||||||
|
os.makedirs(os.path.dirname(path))
|
||||||
|
- subprocess.call(cmd, shell=True)
|
||||||
|
+ subprocess.call(cmd)
|
||||||
|
|
||||||
|
|
||||||
|
def gen_shell(opts, **kwargs):
|
||||||
|
@@ -289,8 +290,7 @@ class Shell(object):
|
||||||
|
'''
|
||||||
|
try:
|
||||||
|
proc = salt.utils.nb_popen.NonBlockingPopen(
|
||||||
|
- cmd,
|
||||||
|
- shell=True,
|
||||||
|
+ self._split_cmd(cmd),
|
||||||
|
stderr=subprocess.PIPE,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
)
|
||||||
|
@@ -369,6 +369,21 @@ class Shell(object):
|
||||||
|
|
||||||
|
return self._run_cmd(cmd)
|
||||||
|
|
||||||
|
+ def _split_cmd(self, cmd):
|
||||||
|
+ """
|
||||||
|
+ Split a command string so that it is suitable to pass to Popen without
|
||||||
|
+ shell=True. This prevents shell injection attacks in the options passed
|
||||||
|
+ to ssh or some other command.
|
||||||
|
+ """
|
||||||
|
+ try:
|
||||||
|
+ ssh_part, cmd_part = cmd.split("/bin/sh")
|
||||||
|
+ except ValueError:
|
||||||
|
+ cmd_lst = shlex.split(cmd)
|
||||||
|
+ else:
|
||||||
|
+ cmd_lst = shlex.split(ssh_part)
|
||||||
|
+ cmd_lst.append("/bin/sh {}".format(cmd_part))
|
||||||
|
+ return cmd_lst
|
||||||
|
+
|
||||||
|
def _run_cmd(self, cmd, key_accept=False, passwd_retries=3):
|
||||||
|
'''
|
||||||
|
Execute a shell command via VT. This is blocking and assumes that ssh
|
||||||
|
@@ -378,8 +393,7 @@ class Shell(object):
|
||||||
|
return '', 'No command or passphrase', 245
|
||||||
|
|
||||||
|
term = salt.utils.vt.Terminal(
|
||||||
|
- cmd,
|
||||||
|
- shell=True,
|
||||||
|
+ self._split_cmd(cmd),
|
||||||
|
log_stdout=True,
|
||||||
|
log_stdout_level='trace',
|
||||||
|
log_stderr=True,
|
||||||
|
diff --git a/salt/modules/tls.py b/salt/modules/tls.py
|
||||||
|
index af845621a3..116b5fe379 100644
|
||||||
|
--- a/salt/modules/tls.py
|
||||||
|
+++ b/salt/modules/tls.py
|
||||||
|
@@ -798,12 +798,13 @@ def create_ca(ca_name,
|
||||||
|
if old_key.strip() == keycontent.strip():
|
||||||
|
write_key = False
|
||||||
|
else:
|
||||||
|
- log.info('Saving old CA ssl key in %s', bck)
|
||||||
|
- with salt.utils.files.fopen(bck, 'w') as bckf:
|
||||||
|
+ log.info('Saving old CA ssl key in {0}'.format(bck))
|
||||||
|
+ fp = os.open(bck, os.O_CREAT | os.O_RDWR, 0o600)
|
||||||
|
+ with os.fdopen(fp, 'w') as bckf:
|
||||||
|
bckf.write(old_key)
|
||||||
|
- os.chmod(bck, 0o600)
|
||||||
|
if write_key:
|
||||||
|
- with salt.utils.files.fopen(ca_keyp, 'wb') as ca_key:
|
||||||
|
+ fp = os.open(ca_keyp, os.O_CREAT | os.O_RDWR, 0o600)
|
||||||
|
+ with os.fdopen(fp, 'wb') as ca_key:
|
||||||
|
ca_key.write(salt.utils.stringutils.to_bytes(keycontent))
|
||||||
|
|
||||||
|
with salt.utils.files.fopen(certp, 'wb') as ca_crt:
|
||||||
|
@@ -1115,9 +1116,9 @@ def create_csr(ca_name,
|
||||||
|
req.sign(key, salt.utils.stringutils.to_str(digest))
|
||||||
|
|
||||||
|
# Write private key and request
|
||||||
|
- with salt.utils.files.fopen('{0}/{1}.key'.format(csr_path,
|
||||||
|
- csr_filename),
|
||||||
|
- 'wb+') as priv_key:
|
||||||
|
+ priv_keyp = '{0}/{1}.key'.format(csr_path, csr_filename)
|
||||||
|
+ fp = os.open(priv_keyp, os.O_CREAT | os.O_RDWR, 0o600)
|
||||||
|
+ with os.fdopen(fp, 'wb+') as priv_key:
|
||||||
|
priv_key.write(
|
||||||
|
salt.utils.stringutils.to_bytes(
|
||||||
|
OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM,
|
||||||
|
@@ -1266,7 +1267,8 @@ def create_self_signed_cert(tls_dir='tls',
|
||||||
|
priv_key_path = '{0}/{1}/certs/{2}.key'.format(cert_base_path(),
|
||||||
|
tls_dir,
|
||||||
|
cert_filename)
|
||||||
|
- with salt.utils.files.fopen(priv_key_path, 'wb+') as priv_key:
|
||||||
|
+ fp = os.open(priv_key_path, os.O_CREAT | os.O_RDWR, 0o600)
|
||||||
|
+ with os.fdopen(fp, 'wb+') as priv_key:
|
||||||
|
priv_key.write(
|
||||||
|
salt.utils.stringutils.to_bytes(
|
||||||
|
OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM,
|
||||||
|
diff --git a/salt/netapi/__init__.py b/salt/netapi/__init__.py
|
||||||
|
index 31a24bb420..4e5b6b093a 100644
|
||||||
|
--- a/salt/netapi/__init__.py
|
||||||
|
+++ b/salt/netapi/__init__.py
|
||||||
|
@@ -3,24 +3,36 @@
|
||||||
|
Make api awesomeness
|
||||||
|
'''
|
||||||
|
from __future__ import absolute_import, print_function, unicode_literals
|
||||||
|
+
|
||||||
|
+import copy
|
||||||
|
+
|
||||||
|
# Import Python libs
|
||||||
|
import inspect
|
||||||
|
+import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Import Salt libs
|
||||||
|
import salt.log # pylint: disable=W0611
|
||||||
|
+import salt.auth
|
||||||
|
import salt.client
|
||||||
|
import salt.config
|
||||||
|
+import salt.daemons.masterapi
|
||||||
|
import salt.runner
|
||||||
|
import salt.syspaths
|
||||||
|
import salt.wheel
|
||||||
|
import salt.utils.args
|
||||||
|
import salt.client.ssh.client
|
||||||
|
import salt.exceptions
|
||||||
|
+import salt.utils.args
|
||||||
|
+import salt.utils.minions
|
||||||
|
+import salt.wheel
|
||||||
|
+from salt.defaults import DEFAULT_TARGET_DELIM
|
||||||
|
|
||||||
|
# Import third party libs
|
||||||
|
from salt.ext import six
|
||||||
|
|
||||||
|
+log = logging.getLogger(__name__)
|
||||||
|
+
|
||||||
|
|
||||||
|
class NetapiClient(object):
|
||||||
|
'''
|
||||||
|
@@ -34,6 +46,15 @@ class NetapiClient(object):
|
||||||
|
|
||||||
|
def __init__(self, opts):
|
||||||
|
self.opts = opts
|
||||||
|
+ apiopts = copy.deepcopy(self.opts)
|
||||||
|
+ apiopts["enable_ssh_minions"] = True
|
||||||
|
+ apiopts["cachedir"] = os.path.join(opts["cachedir"], "saltapi")
|
||||||
|
+ if not os.path.exists(apiopts["cachedir"]):
|
||||||
|
+ os.makedirs(apiopts["cachedir"])
|
||||||
|
+ self.resolver = salt.auth.Resolver(apiopts)
|
||||||
|
+ self.loadauth = salt.auth.LoadAuth(apiopts)
|
||||||
|
+ self.key = salt.daemons.masterapi.access_keys(apiopts)
|
||||||
|
+ self.ckminions = salt.utils.minions.CkMinions(apiopts)
|
||||||
|
|
||||||
|
def _is_master_running(self):
|
||||||
|
'''
|
||||||
|
@@ -55,6 +76,49 @@ class NetapiClient(object):
|
||||||
|
self.opts['sock_dir'],
|
||||||
|
ipc_file))
|
||||||
|
|
||||||
|
+ def _prep_auth_info(self, clear_load):
|
||||||
|
+ sensitive_load_keys = []
|
||||||
|
+ key = None
|
||||||
|
+ if "token" in clear_load:
|
||||||
|
+ auth_type = "token"
|
||||||
|
+ err_name = "TokenAuthenticationError"
|
||||||
|
+ sensitive_load_keys = ["token"]
|
||||||
|
+ return auth_type, err_name, key, sensitive_load_keys
|
||||||
|
+ elif "eauth" in clear_load:
|
||||||
|
+ auth_type = "eauth"
|
||||||
|
+ err_name = "EauthAuthenticationError"
|
||||||
|
+ sensitive_load_keys = ["username", "password"]
|
||||||
|
+ return auth_type, err_name, key, sensitive_load_keys
|
||||||
|
+ raise salt.exceptions.EauthAuthenticationError(
|
||||||
|
+ "No authentication credentials given"
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ def _authorize_ssh(self, low):
|
||||||
|
+ auth_type, err_name, key, sensitive_load_keys = self._prep_auth_info(low)
|
||||||
|
+ auth_check = self.loadauth.check_authentication(low, auth_type, key=key)
|
||||||
|
+ auth_list = auth_check.get("auth_list", [])
|
||||||
|
+ error = auth_check.get("error")
|
||||||
|
+ if error:
|
||||||
|
+ raise salt.exceptions.EauthAuthenticationError(error)
|
||||||
|
+ delimiter = low.get("kwargs", {}).get("delimiter", DEFAULT_TARGET_DELIM)
|
||||||
|
+ _res = self.ckminions.check_minions(
|
||||||
|
+ low["tgt"], low.get("tgt_type", "glob"), delimiter
|
||||||
|
+ )
|
||||||
|
+ minions = _res.get("minions", list())
|
||||||
|
+ missing = _res.get("missing", list())
|
||||||
|
+ authorized = self.ckminions.auth_check(
|
||||||
|
+ auth_list,
|
||||||
|
+ low["fun"],
|
||||||
|
+ low.get("arg", []),
|
||||||
|
+ low["tgt"],
|
||||||
|
+ low.get("tgt_type", "glob"),
|
||||||
|
+ minions=minions,
|
||||||
|
+ )
|
||||||
|
+ if not authorized:
|
||||||
|
+ raise salt.exceptions.EauthAuthenticationError(
|
||||||
|
+ "Authorization error occurred."
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
def run(self, low):
|
||||||
|
'''
|
||||||
|
Execute the specified function in the specified client by passing the
|
||||||
|
@@ -80,6 +144,9 @@ class NetapiClient(object):
|
||||||
|
raise salt.exceptions.EauthAuthenticationError(
|
||||||
|
'Raw shell option not allowed.')
|
||||||
|
|
||||||
|
+ if low['client'] == 'ssh':
|
||||||
|
+ self._authorize_ssh(low)
|
||||||
|
+
|
||||||
|
l_fun = getattr(self, low['client'])
|
||||||
|
f_call = salt.utils.args.format_call(l_fun, low)
|
||||||
|
return l_fun(*f_call.get('args', ()), **f_call.get('kwargs', {}))
|
||||||
|
diff --git a/tests/integration/netapi/test_client.py b/tests/integration/netapi/test_client.py
|
||||||
|
index 08030f31ec..b99bdfe313 100644
|
||||||
|
--- a/tests/integration/netapi/test_client.py
|
||||||
|
+++ b/tests/integration/netapi/test_client.py
|
||||||
|
@@ -1,26 +1,30 @@
|
||||||
|
# encoding: utf-8
|
||||||
|
-
|
||||||
|
# Import Python libs
|
||||||
|
from __future__ import absolute_import, print_function, unicode_literals
|
||||||
|
+import copy
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
|
||||||
|
+import salt.config
|
||||||
|
+import salt.netapi
|
||||||
|
+import salt.utils.files
|
||||||
|
+import salt.utils.platform
|
||||||
|
+import salt.utils.pycrypto
|
||||||
|
+
|
||||||
|
# Import Salt Testing libs
|
||||||
|
from tests.support.paths import TMP_CONF_DIR, TMP
|
||||||
|
from tests.support.runtests import RUNTIME_VARS
|
||||||
|
from tests.support.unit import TestCase, skipIf
|
||||||
|
from tests.support.mock import patch
|
||||||
|
-from tests.support.case import SSHCase
|
||||||
|
+from tests.support.case import ModuleCase, SSHCase
|
||||||
|
+from salt.exceptions import EauthAuthenticationError
|
||||||
|
from tests.support.helpers import (
|
||||||
|
Webserver,
|
||||||
|
SaveRequestsPostHandler,
|
||||||
|
requires_sshd_server
|
||||||
|
)
|
||||||
|
|
||||||
|
-# Import Salt libs
|
||||||
|
-import salt.config
|
||||||
|
-import salt.netapi
|
||||||
|
|
||||||
|
from salt.exceptions import (
|
||||||
|
EauthAuthenticationError
|
||||||
|
@@ -174,6 +178,10 @@ class NetapiSSHClientTest(SSHCase):
|
||||||
|
'''
|
||||||
|
opts = salt.config.client_config(os.path.join(TMP_CONF_DIR, 'master'))
|
||||||
|
self.netapi = salt.netapi.NetapiClient(opts)
|
||||||
|
+ opts = salt.config.client_config(os.path.join(TMP_CONF_DIR, "master"))
|
||||||
|
+ naopts = copy.deepcopy(opts)
|
||||||
|
+ naopts["ignore_host_keys"] = True
|
||||||
|
+ self.netapi = salt.netapi.NetapiClient(naopts)
|
||||||
|
|
||||||
|
self.priv_file = os.path.join(RUNTIME_VARS.TMP_CONF_DIR, 'key_test')
|
||||||
|
self.rosters = os.path.join(RUNTIME_VARS.TMP_CONF_DIR)
|
||||||
|
@@ -271,3 +279,281 @@ class NetapiSSHClientTest(SSHCase):
|
||||||
|
|
||||||
|
self.assertEqual(ret, None)
|
||||||
|
self.assertFalse(os.path.exists('badfile.txt'))
|
||||||
|
+
|
||||||
|
+ @staticmethod
|
||||||
|
+ def cleanup_file(path):
|
||||||
|
+ try:
|
||||||
|
+ os.remove(path)
|
||||||
|
+ except OSError:
|
||||||
|
+ pass
|
||||||
|
+
|
||||||
|
+ @staticmethod
|
||||||
|
+ def cleanup_dir(path):
|
||||||
|
+ try:
|
||||||
|
+ salt.utils.files.rm_rf(path)
|
||||||
|
+ except OSError:
|
||||||
|
+ pass
|
||||||
|
+
|
||||||
|
+ def test_shell_inject_ssh_priv(self):
|
||||||
|
+ """
|
||||||
|
+ Verify CVE-2020-16846 for ssh_priv variable
|
||||||
|
+ """
|
||||||
|
+ # ZDI-CAN-11143
|
||||||
|
+ path = "/tmp/test-11143"
|
||||||
|
+ self.addCleanup(self.cleanup_file, path)
|
||||||
|
+ self.addCleanup(self.cleanup_file, "aaa")
|
||||||
|
+ self.addCleanup(self.cleanup_file, "aaa.pub")
|
||||||
|
+ self.addCleanup(self.cleanup_dir, "aaa|id>")
|
||||||
|
+ low = {
|
||||||
|
+ "roster": "cache",
|
||||||
|
+ "client": "ssh",
|
||||||
|
+ "tgt": "www.zerodayinitiative.com",
|
||||||
|
+ "ssh_priv": "aaa|id>{} #".format(path),
|
||||||
|
+ "fun": "test.ping",
|
||||||
|
+ "eauth": "auto",
|
||||||
|
+ "username": "saltdev_auto",
|
||||||
|
+ "password": "saltdev",
|
||||||
|
+ }
|
||||||
|
+ ret = self.netapi.run(low)
|
||||||
|
+ self.assertFalse(os.path.exists(path))
|
||||||
|
+
|
||||||
|
+ def test_shell_inject_tgt(self):
|
||||||
|
+ """
|
||||||
|
+ Verify CVE-2020-16846 for tgt variable
|
||||||
|
+ """
|
||||||
|
+ # ZDI-CAN-11167
|
||||||
|
+ path = "/tmp/test-11167"
|
||||||
|
+ self.addCleanup(self.cleanup_file, path)
|
||||||
|
+ low = {
|
||||||
|
+ "roster": "cache",
|
||||||
|
+ "client": "ssh",
|
||||||
|
+ "tgt": "root|id>{} #@127.0.0.1".format(path),
|
||||||
|
+ "roster_file": "/tmp/salt-tests-tmpdir/config/roaster",
|
||||||
|
+ "rosters": "/",
|
||||||
|
+ "fun": "test.ping",
|
||||||
|
+ "eauth": "auto",
|
||||||
|
+ "username": "saltdev_auto",
|
||||||
|
+ "password": "saltdev",
|
||||||
|
+ }
|
||||||
|
+ ret = self.netapi.run(low)
|
||||||
|
+ self.assertFalse(os.path.exists(path))
|
||||||
|
+
|
||||||
|
+ def test_shell_inject_ssh_options(self):
|
||||||
|
+ """
|
||||||
|
+ Verify CVE-2020-16846 for ssh_options
|
||||||
|
+ """
|
||||||
|
+ # ZDI-CAN-11169
|
||||||
|
+ path = "/tmp/test-11169"
|
||||||
|
+ self.addCleanup(self.cleanup_file, path)
|
||||||
|
+ low = {
|
||||||
|
+ "roster": "cache",
|
||||||
|
+ "client": "ssh",
|
||||||
|
+ "tgt": "127.0.0.1",
|
||||||
|
+ "renderer": "cheetah",
|
||||||
|
+ "fun": "test.ping",
|
||||||
|
+ "eauth": "auto",
|
||||||
|
+ "username": "saltdev_auto",
|
||||||
|
+ "password": "saltdev",
|
||||||
|
+ "roster_file": "/tmp/salt-tests-tmpdir/config/roaster",
|
||||||
|
+ "rosters": "/",
|
||||||
|
+ "ssh_options": ["|id>{} #".format(path), "lol"],
|
||||||
|
+ }
|
||||||
|
+ ret = self.netapi.run(low)
|
||||||
|
+ self.assertFalse(os.path.exists(path))
|
||||||
|
+
|
||||||
|
+ def test_shell_inject_ssh_port(self):
|
||||||
|
+ """
|
||||||
|
+ Verify CVE-2020-16846 for ssh_port variable
|
||||||
|
+ """
|
||||||
|
+ # ZDI-CAN-11172
|
||||||
|
+ path = "/tmp/test-11172"
|
||||||
|
+ self.addCleanup(self.cleanup_file, path)
|
||||||
|
+ low = {
|
||||||
|
+ "roster": "cache",
|
||||||
|
+ "client": "ssh",
|
||||||
|
+ "tgt": "127.0.0.1",
|
||||||
|
+ "renderer": "cheetah",
|
||||||
|
+ "fun": "test.ping",
|
||||||
|
+ "eauth": "auto",
|
||||||
|
+ "username": "saltdev_auto",
|
||||||
|
+ "password": "saltdev",
|
||||||
|
+ "roster_file": "/tmp/salt-tests-tmpdir/config/roaster",
|
||||||
|
+ "rosters": "/",
|
||||||
|
+ "ssh_port": "hhhhh|id>{} #".format(path),
|
||||||
|
+ }
|
||||||
|
+ ret = self.netapi.run(low)
|
||||||
|
+ self.assertFalse(os.path.exists(path))
|
||||||
|
+
|
||||||
|
+ def test_shell_inject_remote_port_forwards(self):
|
||||||
|
+ """
|
||||||
|
+ Verify CVE-2020-16846 for remote_port_forwards variable
|
||||||
|
+ """
|
||||||
|
+ # ZDI-CAN-11173
|
||||||
|
+ path = "/tmp/test-1173"
|
||||||
|
+ self.addCleanup(self.cleanup_file, path)
|
||||||
|
+ low = {
|
||||||
|
+ "roster": "cache",
|
||||||
|
+ "client": "ssh",
|
||||||
|
+ "tgt": "127.0.0.1",
|
||||||
|
+ "renderer": "cheetah",
|
||||||
|
+ "fun": "test.ping",
|
||||||
|
+ "roster_file": "/tmp/salt-tests-tmpdir/config/roaster",
|
||||||
|
+ "rosters": "/",
|
||||||
|
+ "ssh_remote_port_forwards": "hhhhh|id>{} #, lol".format(path),
|
||||||
|
+ "eauth": "auto",
|
||||||
|
+ "username": "saltdev_auto",
|
||||||
|
+ "password": "saltdev",
|
||||||
|
+ }
|
||||||
|
+ ret = self.netapi.run(low)
|
||||||
|
+ self.assertFalse(os.path.exists(path))
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+@requires_sshd_server
|
||||||
|
+class NetapiSSHClientAuthTest(SSHCase):
|
||||||
|
+
|
||||||
|
+ USERA = "saltdev"
|
||||||
|
+ USERA_PWD = "saltdev"
|
||||||
|
+
|
||||||
|
+ def setUp(self):
|
||||||
|
+ """
|
||||||
|
+ Set up a NetapiClient instance
|
||||||
|
+ """
|
||||||
|
+ opts = salt.config.client_config(os.path.join(TMP_CONF_DIR, "master"))
|
||||||
|
+ naopts = copy.deepcopy(opts)
|
||||||
|
+ naopts["ignore_host_keys"] = True
|
||||||
|
+ self.netapi = salt.netapi.NetapiClient(naopts)
|
||||||
|
+
|
||||||
|
+ self.priv_file = os.path.join(RUNTIME_VARS.TMP_CONF_DIR, "key_test")
|
||||||
|
+ self.rosters = os.path.join(RUNTIME_VARS.TMP_CONF_DIR)
|
||||||
|
+ # Initialize salt-ssh
|
||||||
|
+ self.run_function("test.ping")
|
||||||
|
+ self.mod_case = ModuleCase()
|
||||||
|
+ try:
|
||||||
|
+ add_user = self.mod_case.run_function(
|
||||||
|
+ "user.add", [self.USERA], createhome=False
|
||||||
|
+ )
|
||||||
|
+ self.assertTrue(add_user)
|
||||||
|
+ if salt.utils.platform.is_darwin():
|
||||||
|
+ hashed_password = self.USERA_PWD
|
||||||
|
+ else:
|
||||||
|
+ hashed_password = salt.utils.pycrypto.gen_hash(password=self.USERA_PWD)
|
||||||
|
+ add_pwd = self.mod_case.run_function(
|
||||||
|
+ "shadow.set_password", [self.USERA, hashed_password],
|
||||||
|
+ )
|
||||||
|
+ self.assertTrue(add_pwd)
|
||||||
|
+ except AssertionError:
|
||||||
|
+ self.mod_case.run_function("user.delete", [self.USERA], remove=True)
|
||||||
|
+ self.skipTest("Could not add user or password, skipping test")
|
||||||
|
+
|
||||||
|
+ def tearDown(self):
|
||||||
|
+ del self.netapi
|
||||||
|
+ self.mod_case.run_function("user.delete", [self.USERA], remove=True)
|
||||||
|
+
|
||||||
|
+ @classmethod
|
||||||
|
+ def setUpClass(cls):
|
||||||
|
+ cls.post_webserver = Webserver(handler=SaveRequestsPostHandler)
|
||||||
|
+ cls.post_webserver.start()
|
||||||
|
+ cls.post_web_root = cls.post_webserver.web_root
|
||||||
|
+ cls.post_web_handler = cls.post_webserver.handler
|
||||||
|
+
|
||||||
|
+ @classmethod
|
||||||
|
+ def tearDownClass(cls):
|
||||||
|
+ cls.post_webserver.stop()
|
||||||
|
+ del cls.post_webserver
|
||||||
|
+
|
||||||
|
+ def test_ssh_auth_bypass(self):
|
||||||
|
+ """
|
||||||
|
+ CVE-2020-25592 - Bogus eauth raises exception.
|
||||||
|
+ """
|
||||||
|
+ low = {
|
||||||
|
+ "roster": "cache",
|
||||||
|
+ "client": "ssh",
|
||||||
|
+ "tgt": "127.0.0.1",
|
||||||
|
+ "renderer": "cheetah",
|
||||||
|
+ "fun": "test.ping",
|
||||||
|
+ "roster_file": "/tmp/salt-tests-tmpdir/config/roaster",
|
||||||
|
+ "rosters": "/",
|
||||||
|
+ "eauth": "xx",
|
||||||
|
+ }
|
||||||
|
+ with self.assertRaises(salt.exceptions.EauthAuthenticationError):
|
||||||
|
+ ret = self.netapi.run(low)
|
||||||
|
+
|
||||||
|
+ def test_ssh_auth_valid(self):
|
||||||
|
+ """
|
||||||
|
+ CVE-2020-25592 - Valid eauth works as expected.
|
||||||
|
+ """
|
||||||
|
+ low = {
|
||||||
|
+ "client": "ssh",
|
||||||
|
+ "tgt": "localhost",
|
||||||
|
+ "fun": "test.ping",
|
||||||
|
+ "roster_file": "roster",
|
||||||
|
+ "rosters": [self.rosters],
|
||||||
|
+ "ssh_priv": self.priv_file,
|
||||||
|
+ "eauth": "pam",
|
||||||
|
+ "username": "saltdev",
|
||||||
|
+ "password": "saltdev",
|
||||||
|
+ }
|
||||||
|
+ ret = self.netapi.run(low)
|
||||||
|
+ assert "localhost" in ret
|
||||||
|
+ assert ret["localhost"]["return"] is True
|
||||||
|
+
|
||||||
|
+ def test_ssh_auth_invalid(self):
|
||||||
|
+ """
|
||||||
|
+ CVE-2020-25592 - Wrong password raises exception.
|
||||||
|
+ """
|
||||||
|
+ low = {
|
||||||
|
+ "client": "ssh",
|
||||||
|
+ "tgt": "localhost",
|
||||||
|
+ "fun": "test.ping",
|
||||||
|
+ "roster_file": "roster",
|
||||||
|
+ "rosters": [self.rosters],
|
||||||
|
+ "ssh_priv": self.priv_file,
|
||||||
|
+ "eauth": "pam",
|
||||||
|
+ "username": "saltdev",
|
||||||
|
+ "password": "notvalidpassword",
|
||||||
|
+ }
|
||||||
|
+ with self.assertRaises(salt.exceptions.EauthAuthenticationError):
|
||||||
|
+ ret = self.netapi.run(low)
|
||||||
|
+
|
||||||
|
+ def test_ssh_auth_invalid_acl(self):
|
||||||
|
+ """
|
||||||
|
+ CVE-2020-25592 - Eauth ACL enforced.
|
||||||
|
+ """
|
||||||
|
+ low = {
|
||||||
|
+ "client": "ssh",
|
||||||
|
+ "tgt": "localhost",
|
||||||
|
+ "fun": "at.at",
|
||||||
|
+ "args": ["12:05am", "echo foo"],
|
||||||
|
+ "roster_file": "roster",
|
||||||
|
+ "rosters": [self.rosters],
|
||||||
|
+ "ssh_priv": self.priv_file,
|
||||||
|
+ "eauth": "pam",
|
||||||
|
+ "username": "saltdev",
|
||||||
|
+ "password": "notvalidpassword",
|
||||||
|
+ }
|
||||||
|
+ with self.assertRaises(salt.exceptions.EauthAuthenticationError):
|
||||||
|
+ ret = self.netapi.run(low)
|
||||||
|
+
|
||||||
|
+ def test_ssh_auth_token(self):
|
||||||
|
+ """
|
||||||
|
+ CVE-2020-25592 - Eauth tokens work as expected.
|
||||||
|
+ """
|
||||||
|
+ low = {
|
||||||
|
+ "eauth": "pam",
|
||||||
|
+ "username": "saltdev",
|
||||||
|
+ "password": "saltdev",
|
||||||
|
+ }
|
||||||
|
+ ret = self.netapi.loadauth.mk_token(low)
|
||||||
|
+ assert "token" in ret and ret["token"]
|
||||||
|
+ low = {
|
||||||
|
+ "client": "ssh",
|
||||||
|
+ "tgt": "localhost",
|
||||||
|
+ "fun": "test.ping",
|
||||||
|
+ "roster_file": "roster",
|
||||||
|
+ "rosters": [self.rosters],
|
||||||
|
+ "ssh_priv": self.priv_file,
|
||||||
|
+ "token": ret["token"],
|
||||||
|
+ }
|
||||||
|
+ ret = self.netapi.run(low)
|
||||||
|
+ assert "localhost" in ret
|
||||||
|
+ assert ret["localhost"]["return"] is True
|
||||||
|
--
|
||||||
|
2.28.0
|
||||||
|
|
||||||
|
|
240
fix-novendorchange-option-284.patch
Normal file
240
fix-novendorchange-option-284.patch
Normal file
@ -0,0 +1,240 @@
|
|||||||
|
From f69c1178de003866af412e61e0146597974eec0d Mon Sep 17 00:00:00 2001
|
||||||
|
From: Martin Seidl <mseidl@suse.de>
|
||||||
|
Date: Tue, 27 Oct 2020 16:12:29 +0100
|
||||||
|
Subject: [PATCH] Fix novendorchange option (#284)
|
||||||
|
|
||||||
|
* Fixed novendorchange handling in zypperpkg
|
||||||
|
|
||||||
|
* refactor handling of novendorchange and fix tests
|
||||||
|
---
|
||||||
|
salt/modules/zypperpkg.py | 19 ++--
|
||||||
|
tests/unit/modules/test_zypperpkg.py | 150 ++++++++++++++++++++++++---
|
||||||
|
2 files changed, 148 insertions(+), 21 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/salt/modules/zypperpkg.py b/salt/modules/zypperpkg.py
|
||||||
|
index ad11da4ad1..d84a6af6e0 100644
|
||||||
|
--- a/salt/modules/zypperpkg.py
|
||||||
|
+++ b/salt/modules/zypperpkg.py
|
||||||
|
@@ -1617,7 +1617,7 @@ def upgrade(refresh=True,
|
||||||
|
dryrun=False,
|
||||||
|
dist_upgrade=False,
|
||||||
|
fromrepo=None,
|
||||||
|
- novendorchange=False,
|
||||||
|
+ novendorchange=True,
|
||||||
|
skip_verify=False,
|
||||||
|
no_recommends=False,
|
||||||
|
root=None,
|
||||||
|
@@ -1701,13 +1701,18 @@ def upgrade(refresh=True,
|
||||||
|
log.info('Targeting repos: %s', fromrepo)
|
||||||
|
|
||||||
|
if dist_upgrade:
|
||||||
|
- if novendorchange:
|
||||||
|
- # TODO: Grains validation should be moved to Zypper class
|
||||||
|
- if __grains__['osrelease_info'][0] > 11:
|
||||||
|
- cmd_update.append('--no-allow-vendor-change')
|
||||||
|
- log.info('Disabling vendor changes')
|
||||||
|
+ # TODO: Grains validation should be moved to Zypper class
|
||||||
|
+ if __grains__["osrelease_info"][0] > 11:
|
||||||
|
+ if novendorchange:
|
||||||
|
+ cmd_update.append("--no-allow-vendor-change")
|
||||||
|
+ log.info("Disabling vendor changes")
|
||||||
|
else:
|
||||||
|
- log.warning('Disabling vendor changes is not supported on this Zypper version')
|
||||||
|
+ cmd_update.append("--allow-vendor-change")
|
||||||
|
+ log.info("Enabling vendor changes")
|
||||||
|
+ else:
|
||||||
|
+ log.warning(
|
||||||
|
+ "Enabling/Disabling vendor changes is not supported on this Zypper version"
|
||||||
|
+ )
|
||||||
|
|
||||||
|
if no_recommends:
|
||||||
|
cmd_update.append('--no-recommends')
|
||||||
|
diff --git a/tests/unit/modules/test_zypperpkg.py b/tests/unit/modules/test_zypperpkg.py
|
||||||
|
index a3d20f66d5..8cc84485b5 100644
|
||||||
|
--- a/tests/unit/modules/test_zypperpkg.py
|
||||||
|
+++ b/tests/unit/modules/test_zypperpkg.py
|
||||||
|
@@ -480,7 +480,11 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
|
||||||
|
with patch('salt.modules.zypperpkg.list_pkgs', MagicMock(side_effect=[{"vim": "1.1"}, {"vim": "1.2"}])):
|
||||||
|
ret = zypper.upgrade(dist_upgrade=True)
|
||||||
|
self.assertDictEqual(ret, {"vim": {"old": "1.1", "new": "1.2"}})
|
||||||
|
- zypper_mock.assert_any_call('dist-upgrade', '--auto-agree-with-licenses')
|
||||||
|
+ zypper_mock.assert_any_call(
|
||||||
|
+ "dist-upgrade",
|
||||||
|
+ "--auto-agree-with-licenses",
|
||||||
|
+ "--no-allow-vendor-change",
|
||||||
|
+ )
|
||||||
|
|
||||||
|
with patch('salt.modules.zypperpkg.list_pkgs', MagicMock(side_effect=[{"vim": "1.1"}, {"vim": "1.1"}])):
|
||||||
|
ret = zypper.upgrade(dist_upgrade=True, dryrun=True)
|
||||||
|
@@ -488,25 +492,138 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
|
||||||
|
zypper_mock.assert_any_call('dist-upgrade', '--auto-agree-with-licenses',
|
||||||
|
'--dry-run', '--debug-solver')
|
||||||
|
|
||||||
|
- with patch('salt.modules.zypperpkg.list_pkgs', MagicMock(side_effect=[{"vim": "1.1"}, {"vim": "1.1"}])):
|
||||||
|
- ret = zypper.upgrade(dist_upgrade=True, dryrun=True,
|
||||||
|
- fromrepo=["Dummy", "Dummy2"], novendorchange=True)
|
||||||
|
- zypper_mock.assert_any_call('dist-upgrade', '--auto-agree-with-licenses', '--dry-run',
|
||||||
|
- '--from', "Dummy", '--from', 'Dummy2', '--no-allow-vendor-change')
|
||||||
|
- zypper_mock.assert_any_call('dist-upgrade', '--auto-agree-with-licenses', '--dry-run',
|
||||||
|
- '--from', "Dummy", '--from', 'Dummy2', '--no-allow-vendor-change',
|
||||||
|
- '--debug-solver')
|
||||||
|
-
|
||||||
|
with patch('salt.modules.zypperpkg.list_pkgs', MagicMock(side_effect=[{"vim": "1.1"}, {"vim": "1.1"}])):
|
||||||
|
ret = zypper.upgrade(dist_upgrade=False, fromrepo=["Dummy", "Dummy2"], dryrun=False)
|
||||||
|
zypper_mock.assert_any_call('update', '--auto-agree-with-licenses', '--repo', "Dummy", '--repo', 'Dummy2')
|
||||||
|
|
||||||
|
with patch('salt.modules.zypperpkg.list_pkgs', MagicMock(side_effect=[{"vim": "1.1"}, {"vim": "1.2"}])):
|
||||||
|
ret = zypper.upgrade(dist_upgrade=True, fromrepo=["Dummy", "Dummy2"], novendorchange=True)
|
||||||
|
+ zypper_mock.assert_any_call(
|
||||||
|
+ "dist-upgrade",
|
||||||
|
+ "--auto-agree-with-licenses",
|
||||||
|
+ "--dry-run",
|
||||||
|
+ "--no-allow-vendor-change",
|
||||||
|
+ )
|
||||||
|
+ zypper_mock.assert_any_call(
|
||||||
|
+ "dist-upgrade",
|
||||||
|
+ "--auto-agree-with-licenses",
|
||||||
|
+ "--dry-run",
|
||||||
|
+ "--no-allow-vendor-change",
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ with patch(
|
||||||
|
+ "salt.modules.zypperpkg.list_pkgs",
|
||||||
|
+ MagicMock(side_effect=[{"vim": "1.1"}, {"vim": "1.1"}]),
|
||||||
|
+ ):
|
||||||
|
+ ret = zypper.upgrade(
|
||||||
|
+ dist_upgrade=True,
|
||||||
|
+ dryrun=True,
|
||||||
|
+ fromrepo=["Dummy", "Dummy2"],
|
||||||
|
+ novendorchange=False,
|
||||||
|
+ )
|
||||||
|
+ zypper_mock.assert_any_call(
|
||||||
|
+ "dist-upgrade",
|
||||||
|
+ "--auto-agree-with-licenses",
|
||||||
|
+ "--dry-run",
|
||||||
|
+ "--from",
|
||||||
|
+ "Dummy",
|
||||||
|
+ "--from",
|
||||||
|
+ "Dummy2",
|
||||||
|
+ "--allow-vendor-change",
|
||||||
|
+ )
|
||||||
|
+ zypper_mock.assert_any_call(
|
||||||
|
+ "dist-upgrade",
|
||||||
|
+ "--auto-agree-with-licenses",
|
||||||
|
+ "--dry-run",
|
||||||
|
+ "--from",
|
||||||
|
+ "Dummy",
|
||||||
|
+ "--from",
|
||||||
|
+ "Dummy2",
|
||||||
|
+ "--allow-vendor-change",
|
||||||
|
+ "--debug-solver",
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+ with patch(
|
||||||
|
+ "salt.modules.zypperpkg.list_pkgs",
|
||||||
|
+ MagicMock(side_effect=[{"vim": "1.1"}, {"vim": "1.1"}]),
|
||||||
|
+ ):
|
||||||
|
+ ret = zypper.upgrade(
|
||||||
|
+ dist_upgrade=True,
|
||||||
|
+ dryrun=True,
|
||||||
|
+ fromrepo=["Dummy", "Dummy2"],
|
||||||
|
+ novendorchange=True,
|
||||||
|
+ )
|
||||||
|
+ zypper_mock.assert_any_call(
|
||||||
|
+ "dist-upgrade",
|
||||||
|
+ "--auto-agree-with-licenses",
|
||||||
|
+ "--dry-run",
|
||||||
|
+ "--from",
|
||||||
|
+ "Dummy",
|
||||||
|
+ "--from",
|
||||||
|
+ "Dummy2",
|
||||||
|
+ "--no-allow-vendor-change",
|
||||||
|
+ )
|
||||||
|
+ zypper_mock.assert_any_call(
|
||||||
|
+ "dist-upgrade",
|
||||||
|
+ "--auto-agree-with-licenses",
|
||||||
|
+ "--dry-run",
|
||||||
|
+ "--from",
|
||||||
|
+ "Dummy",
|
||||||
|
+ "--from",
|
||||||
|
+ "Dummy2",
|
||||||
|
+ "--no-allow-vendor-change",
|
||||||
|
+ "--debug-solver",
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ with patch(
|
||||||
|
+ "salt.modules.zypperpkg.list_pkgs",
|
||||||
|
+ MagicMock(side_effect=[{"vim": "1.1"}, {"vim": "1.1"}]),
|
||||||
|
+ ):
|
||||||
|
+ ret = zypper.upgrade(
|
||||||
|
+ dist_upgrade=False, fromrepo=["Dummy", "Dummy2"], dryrun=False
|
||||||
|
+ )
|
||||||
|
+ zypper_mock.assert_any_call(
|
||||||
|
+ "update",
|
||||||
|
+ "--auto-agree-with-licenses",
|
||||||
|
+ "--repo",
|
||||||
|
+ "Dummy",
|
||||||
|
+ "--repo",
|
||||||
|
+ "Dummy2",
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ with patch(
|
||||||
|
+ "salt.modules.zypperpkg.list_pkgs",
|
||||||
|
+ MagicMock(side_effect=[{"vim": "1.1"}, {"vim": "1.2"}]),
|
||||||
|
+ ):
|
||||||
|
+ ret = zypper.upgrade(
|
||||||
|
+ dist_upgrade=True,
|
||||||
|
+ fromrepo=["Dummy", "Dummy2"],
|
||||||
|
+ novendorchange=True,
|
||||||
|
+ )
|
||||||
|
self.assertDictEqual(ret, {"vim": {"old": "1.1", "new": "1.2"}})
|
||||||
|
zypper_mock.assert_any_call('dist-upgrade', '--auto-agree-with-licenses', '--from', "Dummy",
|
||||||
|
'--from', 'Dummy2', '--no-allow-vendor-change')
|
||||||
|
|
||||||
|
+ with patch(
|
||||||
|
+ "salt.modules.zypperpkg.list_pkgs",
|
||||||
|
+ MagicMock(side_effect=[{"vim": "1.1"}, {"vim": "1.2"}]),
|
||||||
|
+ ):
|
||||||
|
+ ret = zypper.upgrade(
|
||||||
|
+ dist_upgrade=True,
|
||||||
|
+ fromrepo=["Dummy", "Dummy2"],
|
||||||
|
+ novendorchange=False,
|
||||||
|
+ )
|
||||||
|
+ self.assertDictEqual(ret, {"vim": {"old": "1.1", "new": "1.2"}})
|
||||||
|
+ zypper_mock.assert_any_call(
|
||||||
|
+ "dist-upgrade",
|
||||||
|
+ "--auto-agree-with-licenses",
|
||||||
|
+ "--from",
|
||||||
|
+ "Dummy",
|
||||||
|
+ "--from",
|
||||||
|
+ "Dummy2",
|
||||||
|
+ "--allow-vendor-change",
|
||||||
|
+ )
|
||||||
|
def test_upgrade_kernel(self):
|
||||||
|
'''
|
||||||
|
Test kernel package upgrade success.
|
||||||
|
@@ -558,10 +675,15 @@ Repository 'DUMMY' not found by its alias, number, or URI.
|
||||||
|
with patch('salt.modules.zypperpkg.list_pkgs', MagicMock(side_effect=[{"vim": "1.1"}, {"vim": "1.1"}])):
|
||||||
|
with self.assertRaises(CommandExecutionError) as cmd_exc:
|
||||||
|
ret = zypper.upgrade(dist_upgrade=True, fromrepo=["DUMMY"])
|
||||||
|
- self.assertEqual(cmd_exc.exception.info['changes'], {})
|
||||||
|
- self.assertEqual(cmd_exc.exception.info['result']['stdout'], zypper_out)
|
||||||
|
- zypper_mock.noraise.call.assert_called_with('dist-upgrade', '--auto-agree-with-licenses',
|
||||||
|
- '--from', 'DUMMY')
|
||||||
|
+ self.assertEqual(cmd_exc.exception.info["changes"], {})
|
||||||
|
+ self.assertEqual(cmd_exc.exception.info["result"]["stdout"], zypper_out)
|
||||||
|
+ zypper_mock.noraise.call.assert_called_with(
|
||||||
|
+ "dist-upgrade",
|
||||||
|
+ "--auto-agree-with-licenses",
|
||||||
|
+ "--from",
|
||||||
|
+ "DUMMY",
|
||||||
|
+ "--no-allow-vendor-change",
|
||||||
|
+ )
|
||||||
|
|
||||||
|
def test_upgrade_available(self):
|
||||||
|
'''
|
||||||
|
--
|
||||||
|
2.28.0
|
||||||
|
|
||||||
|
|
54
path-replace-functools.wraps-with-six.wraps-bsc-1177.patch
Normal file
54
path-replace-functools.wraps-with-six.wraps-bsc-1177.patch
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
From 9707eab7452a94e64f77ece707c31c37e43e47f2 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Alberto Planas <aplanas@suse.com>
|
||||||
|
Date: Tue, 20 Oct 2020 13:13:24 +0200
|
||||||
|
Subject: [PATCH] path: replace functools.wraps with six.wraps
|
||||||
|
(bsc#1177867) (#283)
|
||||||
|
|
||||||
|
Python 2.7 functools.wraps decorator do not add the `__wrapped__`
|
||||||
|
attribute to decorated functions, that is used by Salt to access the
|
||||||
|
original function and deduce the parameters from the signature.
|
||||||
|
|
||||||
|
This patch uses six.wraps, that add this extra attribute.
|
||||||
|
---
|
||||||
|
salt/utils/decorators/path.py | 7 +++----
|
||||||
|
1 file changed, 3 insertions(+), 4 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/salt/utils/decorators/path.py b/salt/utils/decorators/path.py
|
||||||
|
index 8ee7fb1d11..a763c92d22 100644
|
||||||
|
--- a/salt/utils/decorators/path.py
|
||||||
|
+++ b/salt/utils/decorators/path.py
|
||||||
|
@@ -4,11 +4,10 @@ Decorators for salt.utils.path
|
||||||
|
'''
|
||||||
|
from __future__ import absolute_import, print_function, unicode_literals
|
||||||
|
|
||||||
|
-import functools
|
||||||
|
-
|
||||||
|
# Import Salt libs
|
||||||
|
import salt.utils.path
|
||||||
|
from salt.exceptions import CommandNotFoundError
|
||||||
|
+import salt.ext.six
|
||||||
|
|
||||||
|
|
||||||
|
def which(exe):
|
||||||
|
@@ -16,7 +15,7 @@ def which(exe):
|
||||||
|
Decorator wrapper for salt.utils.path.which
|
||||||
|
'''
|
||||||
|
def wrapper(function):
|
||||||
|
- @functools.wraps(function)
|
||||||
|
+ @salt.ext.six.wraps(function)
|
||||||
|
def wrapped(*args, **kwargs):
|
||||||
|
if salt.utils.path.which(exe) is None:
|
||||||
|
raise CommandNotFoundError(
|
||||||
|
@@ -34,7 +33,7 @@ def which_bin(exes):
|
||||||
|
Decorator wrapper for salt.utils.path.which_bin
|
||||||
|
'''
|
||||||
|
def wrapper(function):
|
||||||
|
- @functools.wraps(function)
|
||||||
|
+ @salt.ext.six.wraps(function)
|
||||||
|
def wrapped(*args, **kwargs):
|
||||||
|
if salt.utils.path.which_bin(exes) is None:
|
||||||
|
raise CommandNotFoundError(
|
||||||
|
--
|
||||||
|
2.28.0
|
||||||
|
|
||||||
|
|
34
salt.changes
34
salt.changes
@ -1,3 +1,37 @@
|
|||||||
|
-------------------------------------------------------------------
|
||||||
|
Fri Nov 6 09:19:22 UTC 2020 - Pablo Suárez Hernández <pablo.suarezhernandez@suse.com>
|
||||||
|
|
||||||
|
- Set passphrase for salt-ssh keys to empty string (bsc#1178485)
|
||||||
|
|
||||||
|
- Added:
|
||||||
|
* set-passphrase-for-salt-ssh-keys-to-empty-string-293.patch
|
||||||
|
|
||||||
|
-------------------------------------------------------------------
|
||||||
|
Wed Nov 4 10:54:32 UTC 2020 - Pablo Suárez Hernández <pablo.suarezhernandez@suse.com>
|
||||||
|
|
||||||
|
- Properly validate eauth credentials and tokens on SSH calls made by Salt API
|
||||||
|
(bsc#1178319) (bsc#1178362) (bsc#1178361)
|
||||||
|
(CVE-2020-25592) (CVE-2020-17490) (CVE-2020-16846)
|
||||||
|
|
||||||
|
- Added:
|
||||||
|
* fix-cve-2020-25592-and-add-tests-bsc-1178319.patch
|
||||||
|
|
||||||
|
-------------------------------------------------------------------
|
||||||
|
Tue Oct 27 15:23:12 UTC 2020 - Pablo Suárez Hernández <pablo.suarezhernandez@suse.com>
|
||||||
|
|
||||||
|
- Fix novendorchange handling in zypperpkg module
|
||||||
|
|
||||||
|
- Added:
|
||||||
|
* fix-novendorchange-option-284.patch
|
||||||
|
|
||||||
|
-------------------------------------------------------------------
|
||||||
|
Tue Oct 20 11:43:49 UTC 2020 - Pablo Suárez Hernández <pablo.suarezhernandez@suse.com>
|
||||||
|
|
||||||
|
- Fix disk.blkid to avoid unexpected keyword argument '__pub_user' (bsc#1177867)
|
||||||
|
|
||||||
|
- Added:
|
||||||
|
* path-replace-functools.wraps-with-six.wraps-bsc-1177.patch
|
||||||
|
|
||||||
-------------------------------------------------------------------
|
-------------------------------------------------------------------
|
||||||
Wed Oct 14 10:49:33 UTC 2020 - Pablo Suárez Hernández <pablo.suarezhernandez@suse.com>
|
Wed Oct 14 10:49:33 UTC 2020 - Pablo Suárez Hernández <pablo.suarezhernandez@suse.com>
|
||||||
|
|
||||||
|
12
salt.spec
12
salt.spec
@ -363,6 +363,14 @@ Patch138: fix-grains.test_core-unit-test-277.patch
|
|||||||
Patch139: drop-wrong-mock-from-chroot-unit-test.patch
|
Patch139: drop-wrong-mock-from-chroot-unit-test.patch
|
||||||
# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/280
|
# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/280
|
||||||
Patch140: ensure-virt.update-stop_on_reboot-is-updated-with-it.patch
|
Patch140: ensure-virt.update-stop_on_reboot-is-updated-with-it.patch
|
||||||
|
# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/281
|
||||||
|
Patch141: path-replace-functools.wraps-with-six.wraps-bsc-1177.patch
|
||||||
|
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/58560
|
||||||
|
Patch142: fix-novendorchange-option-284.patch
|
||||||
|
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/58871
|
||||||
|
Patch143: fix-cve-2020-25592-and-add-tests-bsc-1178319.patch
|
||||||
|
# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/293
|
||||||
|
Patch144: set-passphrase-for-salt-ssh-keys-to-empty-string-293.patch
|
||||||
|
|
||||||
BuildRoot: %{_tmppath}/%{name}-%{version}-build
|
BuildRoot: %{_tmppath}/%{name}-%{version}-build
|
||||||
BuildRequires: logrotate
|
BuildRequires: logrotate
|
||||||
@ -1010,6 +1018,10 @@ cp %{S:5} ./.travis.yml
|
|||||||
%patch138 -p1
|
%patch138 -p1
|
||||||
%patch139 -p1
|
%patch139 -p1
|
||||||
%patch140 -p1
|
%patch140 -p1
|
||||||
|
%patch141 -p1
|
||||||
|
%patch142 -p1
|
||||||
|
%patch143 -p1
|
||||||
|
%patch144 -p1
|
||||||
|
|
||||||
%build
|
%build
|
||||||
# Putting /usr/bin at the front of $PATH is needed for RHEL/RES 7. Without this
|
# Putting /usr/bin at the front of $PATH is needed for RHEL/RES 7. Without this
|
||||||
|
31
set-passphrase-for-salt-ssh-keys-to-empty-string-293.patch
Normal file
31
set-passphrase-for-salt-ssh-keys-to-empty-string-293.patch
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
From 677b7a8881a2e9ebab58cead29b1a6d83850c888 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Alexander Graul <mail@agraul.de>
|
||||||
|
Date: Thu, 5 Nov 2020 16:54:44 +0100
|
||||||
|
Subject: [PATCH] Set passphrase for salt-ssh keys to empty string
|
||||||
|
(#293)
|
||||||
|
|
||||||
|
Since the cmd is not passed to a shell anymore, the "" are taken
|
||||||
|
literally and not as an empty string.
|
||||||
|
|
||||||
|
Bugzilla report: https://bugzilla.suse.com/show_bug.cgi?id=1178485
|
||||||
|
---
|
||||||
|
salt/client/ssh/shell.py | 2 +-
|
||||||
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/salt/client/ssh/shell.py b/salt/client/ssh/shell.py
|
||||||
|
index 27aba7b382..27ab9f4f1b 100644
|
||||||
|
--- a/salt/client/ssh/shell.py
|
||||||
|
+++ b/salt/client/ssh/shell.py
|
||||||
|
@@ -44,7 +44,7 @@ def gen_key(path):
|
||||||
|
'''
|
||||||
|
Generate a key for use with salt-ssh
|
||||||
|
'''
|
||||||
|
- cmd = ["ssh-keygen", "-P", '""', "-f", path, "-t", "rsa", "-q"]
|
||||||
|
+ cmd = ["ssh-keygen", "-P", "", "-f", path, "-t", "rsa", "-q"]
|
||||||
|
if not os.path.isdir(os.path.dirname(path)):
|
||||||
|
os.makedirs(os.path.dirname(path))
|
||||||
|
subprocess.call(cmd)
|
||||||
|
--
|
||||||
|
2.28.0
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user