590d18
From f5cf88337d6f775df4a311469b869921bbc90f05 Mon Sep 17 00:00:00 2001
590d18
From: Christian Heimes <cheimes@redhat.com>
590d18
Date: Thu, 30 Jul 2015 15:48:40 +0200
590d18
Subject: [PATCH] Validate vault's file parameters
590d18
590d18
A user can pass file names for password, public and private key files to
590d18
the vault plugin. The plugin attempts to read from these files. If any
590d18
file can't be, an internal error was raised. The patch wraps all reads
590d18
and turns any IOError and UnicodeError into a ValidationError.
590d18
590d18
https://fedorahosted.org/freeipa/ticket/5155
590d18
590d18
Reviewed-By: Martin Basti <mbasti@redhat.com>
590d18
---
590d18
 ipalib/plugins/vault.py | 59 +++++++++++++++++++++++++++++++++++++++----------
590d18
 1 file changed, 47 insertions(+), 12 deletions(-)
590d18
590d18
diff --git a/ipalib/plugins/vault.py b/ipalib/plugins/vault.py
590d18
index 37a32282e7a4e87889eea90d987b737f98fd82c3..fe4eec325dde4a9ecd8a7ce5af1a124fc5c6a9ae 100644
590d18
--- a/ipalib/plugins/vault.py
590d18
+++ b/ipalib/plugins/vault.py
590d18
@@ -19,6 +19,7 @@
590d18
 
590d18
 import base64
590d18
 import getpass
590d18
+import io
590d18
 import json
590d18
 import os
590d18
 import sys
590d18
@@ -210,6 +211,33 @@ EXAMPLES:
590d18
    ipa vault-remove-member <name> --users <usernames>
590d18
 """)
590d18
 
590d18
+
590d18
+def validated_read(argname, filename, mode='r', encoding=None):
590d18
+    """Read file and catch errors
590d18
+
590d18
+    IOError and UnicodeError (for text files) are turned into a
590d18
+    ValidationError
590d18
+    """
590d18
+    try:
590d18
+        with io.open(filename, mode=mode, encoding=encoding) as f:
590d18
+            data = f.read()
590d18
+    except IOError as exc:
590d18
+        raise errors.ValidationError(
590d18
+            name=argname,
590d18
+            error=_("Cannot read file '%(filename)s': %(exc)s") % {
590d18
+                'filename': filename, 'exc': exc[1]
590d18
+                }
590d18
+        )
590d18
+    except UnicodeError as exc:
590d18
+        raise errors.ValidationError(
590d18
+            name=argname,
590d18
+            error=_("Cannot decode file '%(filename)s': %(exc)s") % {
590d18
+                'filename': filename, 'exc': exc
590d18
+                }
590d18
+        )
590d18
+    return data
590d18
+
590d18
+
590d18
 register = Registry()
590d18
 
590d18
 
590d18
@@ -591,8 +619,10 @@ class vault_add(PKQuery, Local):
590d18
                 pass
590d18
 
590d18
             elif password_file:
590d18
-                with open(password_file, 'rb') as f:
590d18
-                    password = f.read().rstrip('\n').decode('utf-8')
590d18
+                password = validated_read('password-file',
590d18
+                                          password_file,
590d18
+                                          encoding='utf-8')
590d18
+                password = password.rstrip('\n')
590d18
 
590d18
             else:
590d18
                 password = self.obj.get_new_password()
590d18
@@ -611,8 +641,9 @@ class vault_add(PKQuery, Local):
590d18
                 pass
590d18
 
590d18
             elif public_key_file:
590d18
-                with open(public_key_file, 'rb') as f:
590d18
-                    public_key = f.read()
590d18
+                public_key = validated_read('public-key-file',
590d18
+                                            public_key_file,
590d18
+                                            mode='rb')
590d18
 
590d18
                 # store vault public key
590d18
                 options['ipavaultpublickey'] = public_key
590d18
@@ -904,8 +935,7 @@ class vault_archive(PKQuery, Local):
590d18
                 reason=_('Input data specified multiple times'))
590d18
 
590d18
         elif input_file:
590d18
-            with open(input_file, 'rb') as f:
590d18
-                data = f.read()
590d18
+            data = validated_read('in', input_file, mode='rb')
590d18
 
590d18
         elif not data:
590d18
             data = ''
590d18
@@ -937,8 +967,10 @@ class vault_archive(PKQuery, Local):
590d18
                 pass
590d18
 
590d18
             elif password_file:
590d18
-                with open(password_file) as f:
590d18
-                    password = f.read().rstrip('\n').decode('utf-8')
590d18
+                password = validated_read('password-file',
590d18
+                                          password_file,
590d18
+                                          encoding='utf-8')
590d18
+                password = password.rstrip('\n')
590d18
 
590d18
             else:
590d18
                 password = self.obj.get_existing_password()
590d18
@@ -1254,8 +1286,10 @@ class vault_retrieve(PKQuery, Local):
590d18
                 pass
590d18
 
590d18
             elif password_file:
590d18
-                with open(password_file) as f:
590d18
-                    password = f.read().rstrip('\n').decode('utf-8')
590d18
+                password = validated_read('password-file',
590d18
+                                          password_file,
590d18
+                                          encoding='utf-8')
590d18
+                password = password.rstrip('\n')
590d18
 
590d18
             else:
590d18
                 password = self.obj.get_existing_password()
590d18
@@ -1277,8 +1311,9 @@ class vault_retrieve(PKQuery, Local):
590d18
                 pass
590d18
 
590d18
             elif private_key_file:
590d18
-                with open(private_key_file, 'rb') as f:
590d18
-                    private_key = f.read()
590d18
+                private_key = validated_read('private-key-file',
590d18
+                                             private_key_file,
590d18
+                                             mode='rb')
590d18
 
590d18
             else:
590d18
                 raise errors.ValidationError(
590d18
-- 
590d18
2.4.3
590d18