[tryton-debian-vcs] tryton-server branch upstream updated. upstream/4.0.3-1-g86b04b1

Mathias Behrle tryton-debian-vcs at alioth.debian.org
Tue Aug 30 14:17:33 UTC 2016


The following commit has been merged in the upstream branch:
https://alioth.debian.org/plugins/scmgit/cgi-bin/gitweb.cgi/?p=tryton/tryton-server.git;a=commitdiff;h=upstream/4.0.3-1-g86b04b1

commit 86b04b1da6148ae4aa571a0cd8606fc13b088c74
Author: Mathias Behrle <mathiasb at m9s.biz>
Date:   Tue Aug 30 14:58:50 2016 +0200

    Adding upstream version 4.0.4.
    
    Signed-off-by: Mathias Behrle <mathiasb at m9s.biz>

diff --git a/CHANGELOG b/CHANGELOG
index 92ccb2c..4aa2e57 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,8 @@
+Version 4.0.4 - 2016-08-30
+* Bug fixes (see mercurial logs for details)
+* Sanitize path in file_open (CVE-2016-1242)
+* Prevent read of user password hash (CVE-2016-1241)
+
 Version 4.0.3 - 2016-08-02
 * Bug fixes (see mercurial logs for details)
 
diff --git a/PKG-INFO b/PKG-INFO
index a71edb7..cfca32d 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: trytond
-Version: 4.0.3
+Version: 4.0.4
 Summary: Tryton server
 Home-page: http://www.tryton.org/
 Author: Tryton
diff --git a/doc/ref/transaction.rst b/doc/ref/transaction.rst
index b212945..282c3f5 100644
--- a/doc/ref/transaction.rst
+++ b/doc/ref/transaction.rst
@@ -45,26 +45,22 @@ commited.
 
     Count the number of modification made in this transaction.
 
-.. method:: Transaction.cursor()
-
-    Returns a cursor object using the ``Transaction.connection``.
-
 .. method:: Transaction.start(database_name, user[, readonly[, context[, close[, autocommit]]]])
 
-    Start a new transaction and return a `context manager`_.
-
-.. method:: Transaction.stop()
-
-    Stop a started transaction and pop it from the stack of transactions.
-
-    This method should not be called directly as it will be by the context
-    manager when exiting the `with` statement.
+    Start a new transaction and return a `context manager`_. The non-readonly
+    transaction will be committed when exiting the `with` statement without
+    exception. The other cases will be rollbacked.
 
 .. method:: Transaction.set_context(context, \**kwargs)
 
     Update the transaction context and return a `context manager`_. The context
     will be restored when exiting the `with` statement.
 
+.. method:: Transaction.reset_context()
+
+    Clear the transaction context and return a `context manager`_. The context
+    will be restored when exiting the `with` statement.
+
 .. method:: Transaction.set_user(user[, set_context])
 
     Modify the user of the transaction and return a `context manager`_.
@@ -82,6 +78,14 @@ commited.
     Create a new transaction with the same database, user and context as the
     original transaction and adds it to the stack of transactions.
 
+.. method:: Transaction.commit()
+
+    Commit the transaction and all data managers associated.
+
+.. method:: Transaction.rollback()
+
+    Rollback the transaction and all data managers associated.
+
 .. method:: Transaction.join(datamanager)
 
     Register in the transaction a data manager conforming to the `Two-Phase
diff --git a/trytond.egg-info/PKG-INFO b/trytond.egg-info/PKG-INFO
index a71edb7..cfca32d 100644
--- a/trytond.egg-info/PKG-INFO
+++ b/trytond.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: trytond
-Version: 4.0.3
+Version: 4.0.4
 Summary: Tryton server
 Home-page: http://www.tryton.org/
 Author: Tryton
diff --git a/trytond/__init__.py b/trytond/__init__.py
index d39c887..50b4167 100644
--- a/trytond/__init__.py
+++ b/trytond/__init__.py
@@ -5,7 +5,7 @@ import time
 import logging
 from email import charset
 
-__version__ = "4.0.3"
+__version__ = "4.0.4"
 logger = logging.getLogger(__name__)
 
 os.environ['TZ'] = 'UTC'
diff --git a/trytond/ir/lang.py b/trytond/ir/lang.py
index f429ffe..f3f1e86 100644
--- a/trytond/ir/lang.py
+++ b/trytond/ir/lang.py
@@ -419,8 +419,9 @@ class Lang(ModelSQL, ModelView):
             format = format.replace('%p',
                 TIME_LOCALE[code]['%p'][datetime.timetuple()[3] < 12 and 0
                     or 1])
+        # Encode and decode under Python2 because strftime use bytes/str.
         if sys.version_info < (3,):
-            format.encode('utf-8')
+            format = format.encode('utf-8')
         result = datetime_strftime(datetime, format)
         if sys.version_info < (3,):
             result = result.decode('utf-8')
diff --git a/trytond/ir/sequence.py b/trytond/ir/sequence.py
index 19a0637..21bc3c1 100644
--- a/trytond/ir/sequence.py
+++ b/trytond/ir/sequence.py
@@ -150,7 +150,7 @@ class Sequence(ModelSQL, ModelView):
 
     @staticmethod
     def default_last_timestamp():
-        return 0.0
+        return 0
 
     @staticmethod
     def default_code():
@@ -248,7 +248,8 @@ class Sequence(ModelSQL, ModelView):
 
         for sequence in sequences:
             next_timestamp = cls._timestamp(sequence)
-            if sequence.last_timestamp > next_timestamp:
+            if (sequence.last_timestamp is not None
+                    and sequence.last_timestamp > next_timestamp):
                 cls.raise_user_error('future_last_timestamp', (
                         sequence.rec_name,))
 
diff --git a/trytond/model/fields/many2many.py b/trytond/model/fields/many2many.py
index 58514e4..74a112e 100644
--- a/trytond/model/fields/many2many.py
+++ b/trytond/model/fields/many2many.py
@@ -162,11 +162,13 @@ class Many2Many(Field):
                         (self.target, 'in', list(sub_ids)),
                         ])
                 for relation in relations:
-                    existing_ids.add(getattr(relation, self.target).id)
+                    existing_ids.add((
+                            getattr(relation, self.origin).id,
+                            getattr(relation, self.target).id))
             for new_id in target_ids:
-                if new_id in existing_ids:
-                    continue
                 for record_id in ids:
+                    if (record_id, new_id) in existing_ids:
+                        continue
                     relation_to_create.append({
                             self.origin: field_value(record_id),
                             self.target: new_id,
diff --git a/trytond/model/modelsql.py b/trytond/model/modelsql.py
index 50482de..33a3d43 100644
--- a/trytond/model/modelsql.py
+++ b/trytond/model/modelsql.py
@@ -756,11 +756,13 @@ class ModelSQL(ModelStorage):
                             _datetime=row[datetime_field]):
                         date_results = field.get([row['id']], cls, field_list,
                             values=[row])
-                    for fname, date_result in date_results.iteritems():
+                    for fname in field_list:
+                        date_result = date_results[fname]
                         row[fname] = date_result[row['id']]
             else:
                 getter_results = field.get(ids, cls, field_list, values=result)
-                for fname, getter_result in getter_results.iteritems():
+                for fname in field_list:
+                    getter_result = getter_results[fname]
                     for row in result:
                         row[fname] = getter_result[row['id']]
 
diff --git a/trytond/model/modelstorage.py b/trytond/model/modelstorage.py
index 4269278..45698d2 100644
--- a/trytond/model/modelstorage.py
+++ b/trytond/model/modelstorage.py
@@ -1434,46 +1434,49 @@ class ModelStorage(Model):
 
     @dualmethod
     def save(cls, records):
-        if not records:
-            return
-        values = {}
-        save_values = {}
-        to_create = []
-        to_write = []
-        transaction = records[0]._transaction
-        user = records[0]._user
-        context = records[0]._context
-        for record in records:
-            assert transaction == record._transaction
-            assert user == record._user
-            assert context == record._context
-            save_values[record] = record._save_values
-            values[record] = record._values
-            record._values = None
-            if record.id is None or record.id < 0:
-                to_create.append(record)
-            elif save_values[record]:
-                to_write.append(record)
-        transaction = Transaction()
-        try:
-            with transaction.set_current_transaction(transaction), \
-                    transaction.set_user(user), \
-                    transaction.set_context(context):
-                if to_create:
-                    news = cls.create([save_values[r] for r in to_create])
-                    for record, new in izip(to_create, news):
-                        record._ids.remove(record.id)
-                        record._id = new.id
-                        record._ids.append(record.id)
-                if to_write:
-                    cls.write(*sum(
-                            (([r], save_values[r]) for r in to_write), ()))
-        except:
+        while records:
+            latter = []
+            values = {}
+            save_values = {}
+            to_create = []
+            to_write = []
+            transaction = records[0]._transaction
+            user = records[0]._user
+            context = records[0]._context
             for record in records:
-                record._values = values[record]
-            raise
-        for record in records:
-            record._init_values = None
+                if (record._transaction != transaction
+                        or user != record._user
+                        or context != record._context):
+                    latter.append(record)
+                    continue
+                save_values[record] = record._save_values
+                values[record] = record._values
+                record._values = None
+                if record.id is None or record.id < 0:
+                    to_create.append(record)
+                elif save_values[record]:
+                    to_write.append(record)
+            transaction = Transaction()
+            try:
+                with transaction.set_current_transaction(transaction), \
+                        transaction.set_user(user), \
+                        transaction.set_context(context):
+                    if to_create:
+                        news = cls.create([save_values[r] for r in to_create])
+                        for record, new in izip(to_create, news):
+                            record._ids.remove(record.id)
+                            record._id = new.id
+                            record._ids.append(record.id)
+                    if to_write:
+                        cls.write(*sum(
+                                (([r], save_values[r]) for r in to_write), ()))
+            except:
+                for record in to_create + to_write:
+                    record._values = values[record]
+                raise
+            for record in to_create + to_write:
+                record._init_values = None
+            records = latter
 
 
 class EvalEnvironment(dict):
diff --git a/trytond/res/user.py b/trytond/res/user.py
index 64d500b..765d0a0 100644
--- a/trytond/res/user.py
+++ b/trytond/res/user.py
@@ -227,6 +227,14 @@ class User(ModelSQL, ModelView):
         return vals
 
     @classmethod
+    def read(cls, ids, fields_names=None):
+        result = super(User, cls).read(ids, fields_names=fields_names)
+        if not fields_names or 'password_hash' in fields_names:
+            for values in result:
+                values['password_hash'] = None
+        return result
+
+    @classmethod
     def create(cls, vlist):
         vlist = [cls._convert_vals(vals) for vals in vlist]
         res = super(User, cls).create(vlist)
diff --git a/trytond/tools/misc.py b/trytond/tools/misc.py
index b1ada39..7983778 100644
--- a/trytond/tools/misc.py
+++ b/trytond/tools/misc.py
@@ -57,6 +57,14 @@ def file_open(name, mode="r", subdir='modules', encoding=None):
         filename = __file__
     root_path = os.path.dirname(os.path.dirname(os.path.abspath(filename)))
 
+    def secure_join(root, *paths):
+        "Join paths and ensure it still below root"
+        path = os.path.join(root, *paths)
+        path = os.path.normpath(path)
+        if not path.startswith(root):
+            raise IOError("Permission denied: %s" % name)
+        return path
+
     egg_name = False
     if subdir == 'modules':
         module_name = name.split(os.sep)[0]
@@ -64,19 +72,19 @@ def file_open(name, mode="r", subdir='modules', encoding=None):
             epoint = EGG_MODULES[module_name]
             mod_path = os.path.join(epoint.dist.location,
                     *epoint.module_name.split('.')[:-1])
-            egg_name = os.path.join(mod_path, name)
+            egg_name = secure_join(mod_path, name)
             if not os.path.isfile(egg_name):
                 # Find module in path
                 for path in sys.path:
                     mod_path = os.path.join(path,
                             *epoint.module_name.split('.')[:-1])
-                    egg_name = os.path.join(mod_path, name)
+                    egg_name = secure_join(mod_path, name)
                     if os.path.isfile(egg_name):
                         break
                 if not os.path.isfile(egg_name):
                     # When testing modules from setuptools location is the
                     # module directory
-                    egg_name = os.path.join(
+                    egg_name = secure_join(
                         os.path.dirname(epoint.dist.location), name)
 
     if subdir:
@@ -84,11 +92,11 @@ def file_open(name, mode="r", subdir='modules', encoding=None):
                 and (name.startswith('ir' + os.sep)
                     or name.startswith('res' + os.sep)
                     or name.startswith('tests' + os.sep))):
-            name = os.path.join(root_path, name)
+            name = secure_join(root_path, name)
         else:
-            name = os.path.join(root_path, subdir, name)
+            name = secure_join(root_path, subdir, name)
     else:
-        name = os.path.join(root_path, name)
+        name = secure_join(root_path, name)
 
     for i in (name, egg_name):
         if i and os.path.isfile(i):
-- 
tryton-server



More information about the tryton-debian-vcs mailing list