Repository: sosreport/sos

Issue:
[ssh] Can ssh plugin check the permissions set for /home/*/.ssh files?
Hello!

When users set wrong permissions to files in their ~/.ssh/ folder, i.e. they set write permission for `~/.ssh/authenticated_keys` for `other`, the SSH server will refuse to accept connections for this user.

I think it would be nice for the [ssh] plugin to check, if the permissions set for files in the `.ssh` folders of system users are correct, or if they are corrupted in some way. 

A very simple solution for that would be to just run `ls -l .ssh/` in every home directory. Would it be OK to extend the ssh plugin to do this? Would it be better to have a separate plugin do this?

Let me know what you think, and I'll give it a try if that's ok :)


Discussion:
Collecting permissions on that file belongs to sos report duty, so in general, I am in favour. And I think `ssh` plugin is a good destination for that. Just several concerns:

- should we  collect just "`ls -lZ .ssh/authenticated_keys`" for all users? Can't listing *whole* directory reveal some sensitive info (I dont know `ssh` and its config enough, to be sure here)?
- how to enumerate all users (or rather their home dirs)? Via `cat /etc/passwd | cut -d: -f6` ?
- should we collect all that info every time, or only when enabled by a plugin option? I *think* these kind of problems are rare, which suggests not collecting it by default. On the other side, collecting that will be fast, so..
As for listing the whole `.ssh` folder or just `.ssh/authenticated_keys`, I'd say we'd want the whole `.ssh` folder. As per this [SO thread](https://superuser.com/questions/215504/permissions-on-private-key-in-ssh-folder) there is more to it than just the `authenticated_keys` file.

Getting list of all users may not be as simple as checking `/etc/passwd`. There is for example `getent passwd` described [here](https://linuxize.com/post/how-to-list-users-in-linux/). I think I'd try to use `getent passwd` and if that fails fall back to `cat /etc/passwd`.

Checking file permissions seems like something we could do every time. I'd be surprised if someone had sensitive information stored in the names of files stored in their `~/.ssh/` directory.

Resolving patch:
diff --git a/sos/report/plugins/ssh.py b/sos/report/plugins/ssh.py
--- a/sos/report/plugins/ssh.py
+++ b/sos/report/plugins/ssh.py
@@ -9,6 +9,7 @@
 # See the LICENSE file in the source distribution for further information.
 
 from sos.report.plugins import Plugin, IndependentPlugin
+import os.path
 
 
 class Ssh(Plugin, IndependentPlugin):
@@ -33,6 +34,10 @@ def setup(self):
         # Include main config files
         self.add_copy_spec(sshcfgs)
 
+        self.included_configs(sshcfgs)
+        self.user_ssh_files_permissions()
+
+    def included_configs(self, sshcfgs):
         # Read configs for any includes and copy those
         try:
             for sshcfg in sshcfgs:
@@ -49,5 +54,33 @@ def setup(self):
         except Exception:
             pass
 
+    def user_ssh_files_permissions(self):
+        """
+        Iterate over .ssh folders in user homes to see their permissions.
+
+        Bad permissions can prevent SSH from allowing access to given user.
+        """
+        users_data = self.exec_cmd('getent passwd')
+
+        if users_data['status']:
+            # If getent fails, fallback to just reading /etc/passwd
+            try:
+                with open('/etc/passwd') as passwd_file:
+                    users_data_lines = passwd_file.readlines()
+            except Exception:
+                # If we can't read /etc/passwd, then there's something wrong.
+                self._log_error("Couldn't read /etc/passwd")
+                return
+        else:
+            users_data_lines = users_data['output'].splitlines()
+
+        # Read the home paths of users in the system and check the ~/.ssh dirs
+        for usr_line in users_data_lines:
+            try:
+                home_dir = os.path.join(usr_line.split(':')[5], '.ssh')
+                if self.path_isdir(home_dir):
+                    self.add_cmd_output('ls -laZ {}'.format(home_dir))
+            except IndexError:
+                pass
 
 # vim: set et ts=4 sw=4 :


Test patch: