]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
Remove password from samba-tool proctitle
authorHeiko Baumann <baumann@hs-koblenz.de>
Tue, 3 Sep 2019 12:30:18 +0000 (14:30 +0200)
committerStefan Metzmacher <metze@samba.org>
Thu, 26 Nov 2020 06:52:41 +0000 (06:52 +0000)
This fix makes sure the password is removed from the proctitle
of samba-tool so it cannot be exposed by e.g. ps(1).
- Moved code to python/samba/getopt.py as suggested by David Mulder
- Except ModuleNotFoundError when trying to load setproctitle module
- Improved code to keep option separator (space or equal sign) while
  removing password from proctitle.

Signed-off-by: Heiko Baumann <heibau@gmail.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: David Mulder <dmulder@suse.com>
python/samba/getopt.py

index 63cd775605cf5b0c554cf6a31385b4cbc3c1042b..f693cde7b314f4a478d9778de33e1d8889bc0c7c 100644 (file)
@@ -164,6 +164,53 @@ class CredentialsOptions(optparse.OptionGroup):
                          callback=self._set_krb5_ccache)
         self.creds = Credentials()
 
+    def _ensure_secure_proctitle(self, opt_str, secret_data, data_type="password"):
+        """ Make sure no sensitive data (e.g. password) resides in proctitle. """
+        import re
+        try:
+            import setproctitle
+        except ModuleNotFoundError:
+            msg = ("WARNING: Using %s on command line is insecure. "
+                    "Please install the setproctitle python module.\n"
+                    % data_type)
+            sys.stderr.write(msg)
+            sys.stderr.flush()
+            return False
+        # Regex to search and replace secret data + option with.
+        #   .*[ ]+  -> Before the option must be one or more spaces.
+        #   [= ]    -> The option and the secret data might be separated by space
+        #              or equal sign.
+        #   [ ]*.*  -> After the secret data might be one, many or no space.
+        pass_opt_re_str = "(.*[ ]+)(%s[= ]%s)([ ]*.*)" % (opt_str, secret_data)
+        pass_opt_re = re.compile(pass_opt_re_str)
+        # Get current proctitle.
+        cur_proctitle = setproctitle.getproctitle()
+        # Make sure we build the correct regex.
+        if not pass_opt_re.match(cur_proctitle):
+            msg = ("Unable to hide %s in proctitle. This is most likely "
+                    "a bug!\n" % data_type)
+            sys.stderr.write(msg)
+            sys.stderr.flush()
+            return False
+        # String to replace secret data with.
+        secret_data_replacer = "xxx"
+        # Build string to replace secret data and option with. And as we dont
+        # want to change anything else than the secret data within the proctitle
+        # we have to check if the option was passed with space or equal sign as
+        # separator.
+        opt_pass_with_eq = "%s=%s" % (opt_str, secret_data)
+        opt_pass_part = re.sub(pass_opt_re_str, r'\2', cur_proctitle)
+        if opt_pass_part == opt_pass_with_eq:
+            replace_str = "%s=%s" % (opt_str, secret_data_replacer)
+        else:
+            replace_str = "%s %s" % (opt_str, secret_data_replacer)
+        # Build new proctitle:
+        new_proctitle = re.sub(pass_opt_re_str,
+                            r'\1' + replace_str + r'\3',
+                            cur_proctitle)
+        # Set new proctitle.
+        setproctitle.setproctitle(new_proctitle)
+
     def _add_option(self, *args1, **kwargs):
         if self.special_name is None:
             return self.add_option(*args1, **kwargs)
@@ -183,6 +230,7 @@ class CredentialsOptions(optparse.OptionGroup):
         self.creds.set_domain(arg)
 
     def _set_password(self, option, opt_str, arg, parser):
+        self._ensure_secure_proctitle(opt_str, arg, "password")
         self.creds.set_password(arg)
         self.ask_for_password = False
         self.machine_pass = False