From: <ke...@us...> - 2006-05-24 16:22:47
|
Revision: 3049 Author: kevca Date: 2006-05-24 09:22:32 -0700 (Wed, 24 May 2006) ViewCVS: http://svn.sourceforge.net/mailmanager/?rev=3049&view=rev Log Message: ----------- Tested fix for Postgres encoding security hole (#1494281) Modified Paths: -------------- MailManager/branches/RELENG_2_0/MailManager.py MailManager/branches/RELENG_2_0/migration.py MailManager/branches/RELENG_2_0/sql/__init__.py Modified: MailManager/branches/RELENG_2_0/MailManager.py =================================================================== --- MailManager/branches/RELENG_2_0/MailManager.py 2006-05-24 16:06:55 UTC (rev 3048) +++ MailManager/branches/RELENG_2_0/MailManager.py 2006-05-24 16:22:32 UTC (rev 3049) @@ -26,7 +26,7 @@ from Products.MailHost.MailHost import manage_addMailHost from Products.PageTemplates.ZopePageTemplate import manage_addPageTemplate from Products.ZSQLMethods.SQL import manage_addZSQLMethod -from Products.MailManager.sql import MailManagerSQL +from Products.MailManager.sql import MailManagerSQL, FSZSQLWrapper, SQLWrapper from MMUserFolder import manage_addMMUserFolder # Python library modules. @@ -335,6 +335,9 @@ print "Adding SQL : %s" % str(self.sqldirclass) self._setObject('sql', self.sqldirclass('sql')) + # Add the ZSQL methods + self.addZSQLMethods() + # Use cookie based authentication. manage_addCC(self, 'Cookie') self.Cookie.auto_login_page = 'Login' @@ -513,23 +516,52 @@ security.declarePublic('getSchemaName') # since I want it from a DTML method def getSchemaName(self): return self.schema.rstrip('.') - - security.declarePublic('account') - def account(self, *args, **kw): - """ Wrapper to allow access to account pluggable brain """ - return self.sql.account(*args, **kw) - security.declarePublic('ticket') - def ticket(self, *args, **kw): - """ Wrapper to allow access to ticket pluggable brain """ - return self.sql.ticket(*args, **kw) + security.declarePrivate('addZSQLMethods') + def addZSQLMethods(self): + """ Add some top level ZSQL methods. - security.declarePublic('attachment') - def attachment(self, *args, **kw): - """ Wrapper to allow access to attachment pluggable brain """ - return self.sql.attachment(*args, **kw) + These are added in manually as SQL objects so that object traversal + will work correctly, and people can access them via http + + The SQLWrapper class includes a fix for the security issue: + Postgres encoding security hole (#1494281) + """ + # Remove and replace ZSQL methods. + sqlmethods = [('ticket', 'id'), ('attachment', 'id'), ('account', 'email')] + for (zsql_method, arguments) in sqlmethods: + if zsql_method in self.objectIds(): + self.manage_delObjects([zsql_method]) + # Load the ZSQL file from disk and save the SQL data into the ZoDB + filename = os.path.join(package_home(globals()), 'sql', 'v2_0', '%s.zsql' % zsql_method) + zsqlfile = open(filename,'r') + + # Remove the ZSQL file header + data = '' + header = True + zsqlline = zsqlfile.readline() + while zsqlline: + if not header: + data = data + zsqlline + if '</dtml-comment>' in zsqlline: + header = False + zsqlline = zsqlfile.readline() + zsqlfile.close() + + zfsm = SQLWrapper(zsql_method, zsql_method, 'mailmanager_db', arguments, data) + self._setObject(zsql_method, zfsm) + + # Set the pluggable brain and allow direct traversal + self.attachment.manage_advanced(1, 1, 0, 'AttachPluggableBrain', + 'MailManager.AttachPluggableBrain', 1) + self.account.manage_advanced(1, 1, 0, 'AccountPluggableBrain', + 'MailManager.AccountPluggableBrain', 1) + self.ticket.manage_advanced(1, 1, 0, 'TicketPluggableBrain', + 'MailManager.TicketPluggableBrain', 1) + + ############################################################################### ############################################################################### Modified: MailManager/branches/RELENG_2_0/migration.py =================================================================== --- MailManager/branches/RELENG_2_0/migration.py 2006-05-24 16:06:55 UTC (rev 3048) +++ MailManager/branches/RELENG_2_0/migration.py 2006-05-24 16:22:32 UTC (rev 3049) @@ -47,6 +47,9 @@ self.manage_delObjects(['sql']) self._setObject('sql', self.sqldirclass('sql')) + # Add the ZSQL methods + self.addZSQLMethods() + # We can't migrate from MailManagers older than 1.0 if self.mversion < 5: return MessageDialog(action='manage_main', message='Migration is only ' @@ -392,6 +395,9 @@ self.manage_delObjects(['sql']) self._setObject('sql', self.sqldirclass('sql')) + # Add the ZSQL methods + self.addZSQLMethods() + self.sql.createCategoryAndTemplateTables() # Migrate the templates @@ -442,6 +448,9 @@ self.manage_delObjects(['sql']) self._setObject('sql', self.sqldirclass('sql')) + # Add the ZSQL methods + self.addZSQLMethods() + # This is the case if we were on 10 < mversion < 12, ie it has # been migrated to PostgreSQL. Yes, the test is icky! try: @@ -459,6 +468,9 @@ self.manage_delObjects(['sql']) self._setObject('sql', self.sqldirclass('sql')) + # Add the ZSQL methods + self.addZSQLMethods() + # Commit the transaction as we don't want to lose all of the migrated # data if the migrateResponseTarget() method raises an exception get_transaction().commit() @@ -475,6 +487,10 @@ # Replace the SQL object to be sure self.manage_delObjects(['sql']) self._setObject('sql', self.sqldirclass('sql')) + + # Add the ZSQL methods + self.addZSQLMethods() + if self.dbplatform == 'mysql': self.configureMySQL() self.sql.setTableCharsets() @@ -485,17 +501,21 @@ if self.mversion < 15: self.manage_delObjects(['sql']) self._setObject('sql', self.sqldirclass('sql')) + + # Add the ZSQL methods + self.addZSQLMethods() + if self.dbplatform == 'mysql': self.configureMySQL() else: self.configurePostgres() if self.mversion < 16: - # Remove ZSQL methods. - # Fix for security issue: Postgres encoding security hole (#1494281) - for zsql_method in ['account', 'attachment', 'ticket']: - if zsql_method in self.objectIds(): - self.manage_delObjects([zsql_method]) + self.manage_delObjects(['sql']) + self._setObject('sql', self.sqldirclass('sql')) + + # Add the ZSQL methods + self.addZSQLMethods() # Update the migration & display versions self.mversion = MailManager.mversion Modified: MailManager/branches/RELENG_2_0/sql/__init__.py =================================================================== --- MailManager/branches/RELENG_2_0/sql/__init__.py 2006-05-24 16:06:55 UTC (rev 3048) +++ MailManager/branches/RELENG_2_0/sql/__init__.py 2006-05-24 16:22:32 UTC (rev 3049) @@ -25,6 +25,12 @@ import OFS.Folder +from AccessControl import ClassSecurityInfo +from Products.FileSystemSite.Permissions import View, ViewManagementScreens +from Products.ZSQLMethods.SQL import SQL + + + class FSZSQLWrapper(FSZSQLMethod): """ A wrapper to an sql method which converts unicode to utf-8 """ @@ -57,19 +63,38 @@ return FSZSQLMethod.__call__(self, *args, **convkw) -class RelativeZSQLMethod(FSZSQLMethod): - """ - Some hacking so that we can use filenames relative to package_home() - """ +class SQLWrapper(SQL): + """ A wrapper to an sql method which converts unicode to utf-8 """ - def __init__(self, id, filepath, fullname=None, properties=None): - pass + def __call__(self, *args, **kw): + + # + # Convert unicode to utf-8 strings + # + # Also Ensure that the combination of 0xc8 ' cannot be used in + # the data sent to the server, to prevent security attacks. See + # bug #1494281 - Postgres encoding security hole + # + # No unicode characters can map to this, so the check is not + # needed when dealing with unicode strings. The encoding + # sequence itself is invalid in utf-8 (which is the only + # internal encoding we would support) so it will just be + # discarded if found. + # - def __getattr__(self, name): - if name == '_filename': - pass + convkw = {} + for key in kw: + if type(kw[key]) is unicode: + convkw[key] = kw[key].encode('utf-8') + elif type(kw[key]) is str: + convkw[key] = kw[key].replace('0xc8\'','') + else: + convkw[key] = kw[key] + # Call method is target folder + return SQL.__call__(self, *args, **convkw) + class MailManagerSQL(OFS.Folder.Folder): def __init__(self, id=None, version='v2_0'): @@ -82,14 +107,6 @@ zfsm = FSZSQLWrapper(method, os.path.join(package_home(globals()), version, '%s.zsql' % method)) self._setObject(method, zfsm) - # Set the pluggable brain and allow direct traversal - self.attachment.manage_advanced(1, 1, 0, 'AttachPluggableBrain', - 'MailManager.AttachPluggableBrain', 1) - self.account.manage_advanced(1, 1, 0, 'AccountPluggableBrain', - 'MailManager.AccountPluggableBrain', 1) - self.ticket.manage_advanced(1, 1, 0, 'TicketPluggableBrain', - 'MailManager.TicketPluggableBrain', 1) - def listCustFolderPaths(self, adding_meta_type=None): return None This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |