The patch fixes the issue described in #5155 as well as a couple of more
potential issues. The vault plugin didn't catch IOError on multiple
occasions.

A user can pass file names for password, public and private key files to
the vault plugin. The plugin attempts to read from these files. If any
file can't be, an internal error was raised. The patch wraps all reads
and turns any IOError and UnicodeError into a ValidationError.

https://fedorahosted.org/freeipa/ticket/5155
From 71b3fcd6862bae2bfc6ea3e6fd38014ed77d4bac Mon Sep 17 00:00:00 2001
From: Christian Heimes <chei...@redhat.com>
Date: Thu, 30 Jul 2015 15:48:40 +0200
Subject: [PATCH] Validate vault's file parameters

A user can pass file names for password, public and private key files to
the vault plugin. The plugin attempts to read from these files. If any
file can't be, an internal error was raised. The patch wraps all reads
and turns any IOError and UnicodeError into a ValidationError.

https://fedorahosted.org/freeipa/ticket/5155
---
 ipalib/plugins/vault.py | 59 +++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 47 insertions(+), 12 deletions(-)

diff --git a/ipalib/plugins/vault.py b/ipalib/plugins/vault.py
index 81197f9328c7ed890fa336f464bfcda475ac6189..423df6b7c0e39c46b20561133be8cd54560bf8b9 100644
--- a/ipalib/plugins/vault.py
+++ b/ipalib/plugins/vault.py
@@ -19,6 +19,7 @@
 
 import base64
 import getpass
+import io
 import json
 import os
 import sys
@@ -210,6 +211,33 @@ EXAMPLES:
    ipa vault-remove-member <name> --users <usernames>
 """)
 
+
+def validated_read(argname, filename, mode='r', encoding=None):
+    """Read file and catch errors
+
+    IOError and UnicodeError (for text files) are turned into a
+    ValidationError
+    """
+    try:
+        with io.open(filename, mode=mode, encoding=encoding) as f:
+            data = f.read()
+    except IOError as exc:
+        raise errors.ValidationError(
+            name=argname,
+            error=_("Cannot read file '%(filename)s': %(exc)s") % {
+                'filename': filename, 'exc': exc[1]
+                }
+        )
+    except UnicodeError as exc:
+        raise errors.ValidationError(
+            name=argname,
+            error=_("Cannot decode file '%(filename)s': %(exc)s") % {
+                'filename': filename, 'exc': exc
+                }
+        )
+    return data
+
+
 register = Registry()
 
 
@@ -591,8 +619,10 @@ class vault_add(PKQuery, Local):
                 pass
 
             elif password_file:
-                with open(password_file, 'rb') as f:
-                    password = f.read().rstrip('\n').decode('utf-8')
+                password = validated_read('password-file',
+                                          password_file,
+                                          encoding='utf-8')
+                password = password.rstrip('\n')
 
             else:
                 password = self.obj.get_new_password()
@@ -611,8 +641,9 @@ class vault_add(PKQuery, Local):
                 pass
 
             elif public_key_file:
-                with open(public_key_file, 'rb') as f:
-                    public_key = f.read()
+                public_key = validated_read('public-key-file',
+                                            public_key_file,
+                                            mode='rb')
 
                 # store vault public key
                 options['ipavaultpublickey'] = public_key
@@ -904,8 +935,7 @@ class vault_archive(PKQuery, Local):
                 reason=_('Input data specified multiple times'))
 
         elif input_file:
-            with open(input_file, 'rb') as f:
-                data = f.read()
+            data = validated_read('in', input_file, mode='rb')
 
         elif not data:
             data = ''
@@ -937,8 +967,10 @@ class vault_archive(PKQuery, Local):
                 pass
 
             elif password_file:
-                with open(password_file) as f:
-                    password = f.read().rstrip('\n').decode('utf-8')
+                password = validated_read('password-file',
+                                          password_file,
+                                          encoding='utf-8')
+                password = password.rstrip('\n')
 
             else:
                 password = self.obj.get_existing_password()
@@ -1254,8 +1286,10 @@ class vault_retrieve(PKQuery, Local):
                 pass
 
             elif password_file:
-                with open(password_file) as f:
-                    password = f.read().rstrip('\n').decode('utf-8')
+                password = validated_read('password-file',
+                                          password_file,
+                                          encoding='utf-8')
+                password = password.rstrip('\n')
 
             else:
                 password = self.obj.get_existing_password()
@@ -1277,8 +1311,9 @@ class vault_retrieve(PKQuery, Local):
                 pass
 
             elif private_key_file:
-                with open(private_key_file, 'rb') as f:
-                    private_key = f.read()
+                private_key = validated_read('private-key-file',
+                                             private_key_file,
+                                             mode='rb')
 
             else:
                 raise errors.ValidationError(
-- 
2.4.3

Attachment: signature.asc
Description: OpenPGP digital signature

-- 
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code

Reply via email to