attachments, in order:
(1) 0...the  proposed patch to sugar
(2) suga..9.1  sugar part of a draft patch for 9.1, only read it if you're
interested, scarcely tested.
(3) 0...s-l   proposed patch for sugar-toolkit
(4) tool...9.1  the sugar-toolkit part of the draft 9.1 patch
(5) 0...fixes   some minor pylint cleanup to sugar, to be applied after
patch 1 above.

So, the important parts here are (1) and (3). Patch (1) makes sugar registry
service not add bundles unless they're in ~/Activities. (The registry can
add such bundles, but the service will refuse to). Patch (3) makes
activitybundle.py refuse to install loopholed activities unless called with
securitycheck=False.
From 4db7faf72edc7eaa2aa4631a98aa29819f2e5ec8 Mon Sep 17 00:00:00 2001
From: Jameson Quinn <[EMAIL PROTECTED]>
Date: Mon, 4 Aug 2008 19:17:11 -0600
Subject: [PATCH] bug #5657 - don't add bundles to registry unless they're in ~/Activities

---
 service/bundleregistry.py |    7 +++++--
 1 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/service/bundleregistry.py b/service/bundleregistry.py
index e7c30a8..5d3fec8 100644
--- a/service/bundleregistry.py
+++ b/service/bundleregistry.py
@@ -174,12 +174,15 @@ class BundleRegistry(gobject.GObject):
         bundle_dirs.sort(lambda d1, d2: cmp(bundles[d1], bundles[d2]))
         for folder in bundle_dirs:
             try:
-                self.add_bundle(folder)
+                self.add_bundle(folder, securitycheck=False)
             except Exception, e:
                 logging.error('Error while processing installed activity ' \
                               'bundle: %s, %s, %s' % (folder, e.__class__, e))
 
-    def add_bundle(self, bundle_path):
+    def add_bundle(self, bundle_path, securitycheck=True):
+        if securitycheck and not bundle_path.startswith(
+                                    os.path.expanduser("~/Activities")):
+            return False
         try:
             bundle = ActivityBundle(bundle_path)
         except MalformedBundleException:
-- 
1.5.2.5

diff --git a/service/activityregistryservice.py b/service/activityregistryservice.py
index 6ba5598..7b3415a 100644
--- a/service/activityregistryservice.py
+++ b/service/activityregistryservice.py
@@ -24,6 +24,11 @@ _ACTIVITY_REGISTRY_SERVICE_NAME = 'org.laptop.ActivityRegistry'
 _ACTIVITY_REGISTRY_IFACE = 'org.laptop.ActivityRegistry'
 _ACTIVITY_REGISTRY_PATH = '/org/laptop/ActivityRegistry'
 
+def log_it(s):
+    f = file("/home/chema/.sugar/default/logs/hardcoded","ab")
+    f.write(s+"\n")
+    f.close()
+
 class ActivityRegistry(dbus.service.Object):
     def __init__(self):
         bus = dbus.SessionBus()
@@ -64,11 +69,8 @@ class ActivityRegistry(dbus.service.Object):
     @dbus.service.method(_ACTIVITY_REGISTRY_IFACE,
                          in_signature='', out_signature='aa{sv}')
     def GetActivities(self):
-        result = []
         registry = bundleregistry.get_registry()
-        for bundle in registry:
-            result.append(self._bundle_to_dict(bundle))
-        return result
+        return (bundle for bundle in registry)
 
     @dbus.service.method(_ACTIVITY_REGISTRY_IFACE,
                          in_signature='s', out_signature='a{sv}')
@@ -78,7 +80,8 @@ class ActivityRegistry(dbus.service.Object):
         if not bundle:
             return {}
         
-        return self._bundle_to_dict(bundle)
+        log_it("service about to return "+str(bundle))
+        return bundle
 
     @dbus.service.method(_ACTIVITY_REGISTRY_IFACE,
                          in_signature='s', out_signature='aa{sv}')
@@ -90,18 +93,15 @@ class ActivityRegistry(dbus.service.Object):
             name = bundle.get_name().lower()
             bundle_id = bundle.get_bundle_id().lower()
             if name.find(key) != -1 or bundle_id.find(key) != -1:
-                result.append(self._bundle_to_dict(bundle))
+                result.append(bundle)
 
         return result
 
     @dbus.service.method(_ACTIVITY_REGISTRY_IFACE,
                          in_signature='s', out_signature='aa{sv}')
     def GetActivitiesForType(self, mime_type):
-        result = []
         registry = bundleregistry.get_registry()
-        for bundle in registry.get_activities_for_type(mime_type):
-            result.append(self._bundle_to_dict(bundle))
-        return result
+        return registry.get_activities_for_type(mime_type)
 
     @dbus.service.method(_ACTIVITY_REGISTRY_IFACE,
                          in_signature='sib', out_signature='')
@@ -127,32 +127,14 @@ class ActivityRegistry(dbus.service.Object):
     def ActivityChanged(self, activity_info):
         pass
 
-    def _bundle_to_dict(self, bundle):
-        registry = bundleregistry.get_registry()
-        favorite = registry.is_bundle_favorite(bundle.get_bundle_id(),
-                                               bundle.get_activity_version())
-        x, y = registry.get_bundle_position(bundle.get_bundle_id(),
-                                            bundle.get_activity_version())
-        return {'name': bundle.get_name(),
-                'icon': bundle.get_icon(),
-                'bundle_id': bundle.get_bundle_id(),
-                'version': bundle.get_activity_version(),
-                'path': bundle.get_path(),
-                'command': bundle.get_command(),
-                'show_launcher': bundle.get_show_launcher(),
-                'favorite': favorite,
-                'installation_time': bundle.get_installation_time(),
-                'position_x': x,
-                'position_y': y}
-
-    def _bundle_added_cb(self, bundle_registry, bundle):
-        self.ActivityAdded(self._bundle_to_dict(bundle))
-
-    def _bundle_removed_cb(self, bundle_registry, bundle):
-        self.ActivityRemoved(self._bundle_to_dict(bundle))
-
-    def _bundle_changed_cb(self, bundle_registry, bundle):
-        self.ActivityChanged(self._bundle_to_dict(bundle))
+    def _bundle_added_cb(self, bundle_registry, bundledict):
+        self.ActivityAdded(bundledict)
+
+    def _bundle_removed_cb(self, bundle_registry, bundledict):
+        self.ActivityRemoved(bundledict)
+
+    def _bundle_changed_cb(self, bundle_registry, bundledict):
+        self.ActivityChanged(bundledict)
 
 _instance = None
 
diff --git a/service/bundleregistry.py b/service/bundleregistry.py
index e7c30a8..e1556de 100644
--- a/service/bundleregistry.py
+++ b/service/bundleregistry.py
@@ -20,6 +20,7 @@ import traceback
 
 import gobject
 import simplejson
+import dbus
 
 from sugar.bundle.activitybundle import ActivityBundle
 from sugar.bundle.bundle import MalformedBundleException
@@ -27,6 +28,8 @@ from sugar import env
 
 import config
 
+VALID_BITFROST = set("P_ROOT")
+
 class BundleRegistry(gobject.GObject):
     """Service that tracks the available activity bundles"""
 
@@ -42,9 +45,10 @@ class BundleRegistry(gobject.GObject):
     def __init__(self):
         gobject.GObject.__init__(self)
 
+        
         self._mime_defaults = self._load_mime_defaults()
 
-        self._bundles = []
+        self._bundles = {}
         for activity_dir in self._get_activity_directories():
             self._scan_directory(activity_dir)
 
@@ -58,6 +62,9 @@ class BundleRegistry(gobject.GObject):
                     % traceback.format_exc())
 
         self._merge_default_favorites()
+        
+        self._bundledict_cache = {}
+        self._typebundle_cache = {}
 
     def _get_activity_directories(self):
         directories = []
@@ -87,7 +94,7 @@ class BundleRegistry(gobject.GObject):
         because JSON doesn't support tuples and python won't accept a list
         as a dictionary key.
         """
-        if ' ' in bundle_id:
+        if ' ' in str(bundle_id):
             raise ValueError('bundle_id cannot contain spaces')
         return '%s %s' % (bundle_id, version)
 
@@ -130,7 +137,7 @@ class BundleRegistry(gobject.GObject):
 
         for bundle_id in default_activities:
             max_version = -1
-            for bundle in self._bundles:
+            for bundle in self._bundles.itervalues():
                 if bundle.get_bundle_id() == bundle_id and \
                         max_version < bundle.get_activity_version():
                     max_version = bundle.get_activity_version()
@@ -144,14 +151,14 @@ class BundleRegistry(gobject.GObject):
         self._write_favorites_file()
 
     def get_bundle(self, bundle_id):
-        """Returns an bundle given his service name"""
-        for bundle in self._bundles:
+        """Returns an bundle given its service name"""
+        for bundle in self._bundles.itervalues():
             if bundle.get_bundle_id() == bundle_id:
-                return bundle
+                return self._bundle_to_dict(bundle)
         return None
     
     def __iter__(self):
-        return self._bundles.__iter__()
+        return (self._bundle_to_dict(bundle) for bundle in self._bundles.itervalues())
 
     def _scan_directory(self, path):
         if not os.path.isdir(path):
@@ -174,56 +181,72 @@ class BundleRegistry(gobject.GObject):
         bundle_dirs.sort(lambda d1, d2: cmp(bundles[d1], bundles[d2]))
         for folder in bundle_dirs:
             try:
-                self.add_bundle(folder)
+                self.add_bundle(folder, securitycheck=False)
             except Exception, e:
                 logging.error('Error while processing installed activity ' \
                               'bundle: %s, %s, %s' % (folder, e.__class__, e))
-
+                
     def add_bundle(self, bundle_path):
         try:
             bundle = ActivityBundle(bundle_path)
         except MalformedBundleException:
             return False
 
-        self._bundles.append(bundle)
-        self.emit('bundle-added', bundle)
+        key = self._get_favorite_key(bundle.get_bundle_id(),
+                                     bundle.get_activity_version())
+        if key in self._bundles:
+            oldpath = self._bundles[key].get_path()
+            logging.error('Adding bundle with duplicate key: %s, %s' %
+                          (bundle_path, key, oldpath))
+            #now keep the older one - more stable.
+            if os.stat(oldpath).st_ctime < os.stat(bundle_path).st_ctime:
+                return False
+        self._bundles[key] = bundle
+        if self._typebundle_cache:
+            self._update_caches(key, remove=False)
+        self.emit('bundle-added', self._bundle_to_dict(bundle))
         return True
 
     def remove_bundle(self, bundle_path):
-        for bundle in self._bundles:
+        for key, bundle in self._bundles.iteritems():
             if bundle.get_path() == bundle_path:
-                self._bundles.remove(bundle)
-                self.emit('bundle-removed', bundle)
+                self._update_caches(key, remove=True)
+                bundle = self._bundles.pop(key)
+                self.emit('bundle-removed', self._bundle_to_dict(bundle))
                 return True
         return False
 
     def get_activities_for_type(self, mime_type):
+        if mime_type in self._typebundle_cache:
+            return self._typebundle_cache[mime_type]
         result = []
-        for bundle in self._bundles:
-            if bundle.get_mime_types() and mime_type in bundle.get_mime_types():
+        for bundle in self._bundles.itervalues():
+            types = bundle.get_mime_types()
+            if types and mime_type in types:
                 if self.get_default_for_type(mime_type) == \
                         bundle.get_bundle_id():
-                    result.insert(0, bundle)
+                    result.insert(0, self._bundle_to_dict(bundle))
                 else:
-                    result.append(bundle)
+                    result.append(self._bundle_to_dict(bundle))
+        self._typebundle_cache[mime_type] = result
         return result
 
     def get_default_for_type(self, mime_type):
         if self._mime_defaults.has_key(mime_type):
-            return self._mime_defaults[mime_type]
+            return self._bundle_to_dict(self._mime_defaults[mime_type])
         else:
             return None
 
     def _find_bundle(self, bundle_id, version):
-        for bundle in self._bundles:
-            if bundle.get_bundle_id() == bundle_id and \
-                    bundle.get_activity_version() == version:
-                return bundle
+        key = self._get_favorite_key(bundle_id, version)
+        if key in self._bundles:
+            return self._bundles[key]
         raise ValueError('No bundle %r with version %r exists.' % \
                 (bundle_id, version))
 
     def set_bundle_favorite(self, bundle_id, version, favorite):
         key = self._get_favorite_key(bundle_id, version)
+        self._update_caches(key, remove=True)
         if favorite and not key in self._favorite_bundles:
             self._favorite_bundles[key] = None
         elif not favorite and key in self._favorite_bundles:
@@ -233,14 +256,15 @@ class BundleRegistry(gobject.GObject):
 
         self._write_favorites_file()
         bundle = self._find_bundle(bundle_id, version)
-        self.emit('bundle-changed', bundle)
+        self.emit('bundle-changed', self._bundle_to_dict(bundle))
 
-    def is_bundle_favorite(self, bundle_id, version):
-        key = self._get_favorite_key(bundle_id, version)
+    def is_bundle_favorite(self, key):
         return key in self._favorite_bundles
 
     def set_bundle_position(self, bundle_id, version, x, y):
         key = self._get_favorite_key(bundle_id, version)
+        self._bundledict_cache.pop(key, none)
+        #_typebundle_cache has this data too but so what?
         if key not in self._favorite_bundles:
             raise ValueError('Bundle %s %s not favorite' % (bundle_id, version))
 
@@ -254,25 +278,90 @@ class BundleRegistry(gobject.GObject):
 
         self._write_favorites_file()
         bundle = self._find_bundle(bundle_id, version)
-        self.emit('bundle-changed', bundle)
+        self.emit('bundle-changed', self._bundle_to_dict(bundle))
 
-    def get_bundle_position(self, bundle_id, version):
+    def get_bundle_position(self, key):
         """Get the coordinates where the user wants the representation of this
         bundle to be displayed. Coordinates are relative to a 1000x1000 area.
         """
-        key = self._get_favorite_key(bundle_id, version)
         if key not in self._favorite_bundles or \
                 self._favorite_bundles[key] is None or \
                 'position' not in self._favorite_bundles[key]:
             return (-1, -1)
         else:
             return tuple(self._favorite_bundles[key]['position'])
+    
+    def _invalidate_caches(self):
+        self._bundledict_cache = {}
+        self._typebundle_cache = {}
+        
+    def _update_caches(self, key, remove):
+        """Fix the caches to add a bundle or remove it.
+        
+        NOTE: call this BEFORE you remove a key from self._bundles
+        
+        remove: True to remove or change, False to add."""
+        if remove:
+            self._bundledict_cache.pop(key,None)
+        #else: be lazy
+        
+        types = bundle.get_mime_types()
+        for type in types:
+            if type in self._typebundle_cache:
+                if remove:
+                    del self._typebundle_cache[type]
+                else:
+                    self._typebundle_cache[type] += (self._bundle_to_dict(bundle),)
 
     def _write_favorites_file(self):
         path = env.get_profile_path('favorite_activities')
         favorites_data = {'defaults-mtime': self._last_defaults_mtime,
                           'favorites': self._favorite_bundles}
         simplejson.dump(favorites_data, open(path, 'w'), indent=1)
+        
+    def _validate_bitfrost(self, bundle):
+        requested = bundle.get_bitfrost_requests().intersection(VALID_BITFROST)
+#        if "P_ROOT" in requested:
+#            #only allow root for .../share/sugar/activities
+#            #do not check full path for jhbuild compatibility.
+#            path = os.path.split(bundle.get_path())
+#            if path[-4:-1] != ["share", "sugar", "activities"]:
+#                requested = requested.difference(["P_ROOT"])
+#                
+#            #only allow root if owner is the same as owner of this module,
+#            #and permissions are same or tighter.    
+#            else:
+#                bundle_s = os.stat(path)
+#                thismod_s = os.stat(sys.modules[__name__].__file__)
+#                if (bundle_s.st_uid != thismod_s.st_uid or
+#                      ((bundle_s.st_mode | thismod_s.st_mode) > 
+#                         thismod_s.st_mode)):
+#                    requested = requested.difference(["P_ROOT"])
+        return requested
+
+    def _bundle_to_dict(self, bundle):
+        key = self._get_favorite_key(bundle.get_bundle_id(),
+                                     bundle.get_activity_version())
+        if key not in self._bundledict_cache:
+            favorite = self.is_bundle_favorite(key)
+            x, y = self.get_bundle_position(key)
+            result = {'name': bundle.get_name(),
+                      'icon': bundle.get_icon(),
+                      'bundle_id': bundle.get_bundle_id(),
+                      'version': bundle.get_activity_version(),
+                      'path': bundle.get_path(),
+                      'command': bundle.get_command(),
+                      'show_launcher': bundle.get_show_launcher(),
+                      'favorite': favorite,
+                      'installation_time': bundle.get_installation_time(),
+                      'position_x': x,
+                      'position_y': y,
+                      'bitfrost': dbus.Array(self._validate_bitfrost(bundle),
+                                             signature="as")}
+            self._bundledict_cache[key] = result
+            return result
+        else:
+            return self._bundledict_cache[key]
 
 _instance = None
 
From 0e7977843908d805fdf07b4466b1c87a6ffdf379 Mon Sep 17 00:00:00 2001
From: Jameson Quinn <[EMAIL PROTECTED]>
Date: Wed, 6 Aug 2008 10:38:44 -0600
Subject: [PATCH] bug #5657: don't install applications in Rainbow's loophole, unless forced

---
 src/sugar/activity/activityfactory.py |   12 +++++++-----
 src/sugar/bundle/activitybundle.py    |    7 ++++++-
 2 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/src/sugar/activity/activityfactory.py b/src/sugar/activity/activityfactory.py
index 4d6871f..c94ff5d 100644
--- a/src/sugar/activity/activityfactory.py
+++ b/src/sugar/activity/activityfactory.py
@@ -54,6 +54,12 @@ _RAINBOW_SERVICE_NAME = "org.laptop.security.Rainbow"
 _RAINBOW_ACTIVITY_FACTORY_PATH = "/"
 _RAINBOW_ACTIVITY_FACTORY_INTERFACE = "org.laptop.security.Rainbow"
 
+RAINBOW_LOOPHOLE_LIST = [ 'org.laptop.JournalActivity',
+                             'org.laptop.Terminal',
+                             'org.laptop.Log',
+                             'org.laptop.Analyze'
+                             ]
+
 _children_pid = []
 
 def _sigchild_handler(signum, frame):
@@ -193,11 +199,7 @@ class ActivityCreationHandler(gobject.GObject):
         self._handle = handle
 
         self._use_rainbow = os.path.exists('/etc/olpc-security')
-        if service_name in [ 'org.laptop.JournalActivity',
-                             'org.laptop.Terminal',
-                             'org.laptop.Log',
-                             'org.laptop.Analyze'
-                             ]:
+        if service_name in RAINBOW_LOOPHOLE_LIST:
             self._use_rainbow = False                    
     
         bus = dbus.SessionBus()
diff --git a/src/sugar/bundle/activitybundle.py b/src/sugar/bundle/activitybundle.py
index 2c235d8..25f8f9e 100644
--- a/src/sugar/bundle/activitybundle.py
+++ b/src/sugar/bundle/activitybundle.py
@@ -352,7 +352,12 @@ class ActivityBundle(Bundle):
                                             os.path.basename(info_file)))
         return install_path
 
-    def install(self):
+    def install(self, securitycheck=True):
+        if securitycheck:
+            from sugar.activity.activityfactory import RAINBOW_LOOPHOLE_LIST
+            if self._bundle_id in RAINBOW_LOOPHOLE_LIST:
+                raise MalformedBundleException(
+                        "No privileges to install a P_ROOT activity")
         activities_path = env.get_user_activities_path()
         act = activity.get_registry().get_activity(self._bundle_id)
         if act is not None and act.path.startswith(activities_path):
-- 
1.5.2.5

diff --git a/src/sugar/activity/activityfactory.py b/src/sugar/activity/activityfactory.py
index 4d6871f..9912ca5 100644
--- a/src/sugar/activity/activityfactory.py
+++ b/src/sugar/activity/activityfactory.py
@@ -29,7 +29,7 @@ from sugar.activity import registry
 from sugar import util
 from sugar import env
 
-from errno import EEXIST
+from errno import EEXIST, ENOSPC
 
 import os
 
@@ -150,6 +150,9 @@ def open_log_file(activity):
         except OSError, e:
             if e.errno == EEXIST:
                 i += 1
+            elif e.errno == ENOSPC:
+                # not the end of the world; let's try to keep going.
+                return ('/dev/null', open('/dev/null','w'))
             else:
                 raise e
 
@@ -241,11 +244,9 @@ class ActivityCreationHandler(gobject.GObject):
                                   self._handle.object_id,
                                   self._handle.uri)
 
-            if not self._use_rainbow:
-                p = subprocess.Popen(command, env=environ, cwd=activity.path,
-                                     stdout=log_file, stderr=log_file)
-                _children_pid.append(p.pid)
-            else:
+            use_rainbow = (os.path.exists('/etc/olpc-security') and
+                           "P_ROOT" in activity["bitfrost"])
+            if use_rainbow:
                 log_file.close()
                 system_bus = dbus.SystemBus()
                 factory = system_bus.get_object(_RAINBOW_SERVICE_NAME,
@@ -260,6 +261,10 @@ class ActivityCreationHandler(gobject.GObject):
                         reply_handler=self._create_reply_handler,
                         error_handler=self._create_error_handler,
                         dbus_interface=_RAINBOW_ACTIVITY_FACTORY_INTERFACE)
+            else:
+                p = subprocess.Popen(command, env=environ, cwd=activity.path,
+                                     stdout=log_file, stderr=log_file)
+                _children_pid.append(p.pid)
 
     def _no_reply_handler(self, *args):
         pass
diff --git a/src/sugar/activity/registry.py b/src/sugar/activity/registry.py
index da2eb27..cc78b19 100644
--- a/src/sugar/activity/registry.py
+++ b/src/sugar/activity/registry.py
@@ -27,17 +27,13 @@ _ACTIVITY_REGISTRY_PATH = '/org/laptop/ActivityRegistry'
 
 def _activity_info_from_dict(info_dict):
     if not info_dict:
-        return None
-    return ActivityInfo(info_dict['name'], info_dict['icon'],
-                        info_dict['bundle_id'], info_dict['version'],
-                        info_dict['path'], info_dict['show_launcher'],
-                        info_dict['command'], info_dict['favorite'],
-                        info_dict['installation_time'],
-                        info_dict['position_x'], info_dict['position_y'])
+        return {}
+    return ActivityInfo(**dict((str(key),val)
+                               for key,val in info_dict.iteritems()))
 
 class ActivityInfo(object):
-    def __init__(self, name, icon, bundle_id, version, path, show_launcher,
-                 command, favorite, installation_time, position_x, position_y):
+    """A convenience class whose members are:
+    
         self.name = name
         self.icon = icon
         self.bundle_id = bundle_id
@@ -48,6 +44,12 @@ class ActivityInfo(object):
         self.favorite = favorite
         self.installation_time = installation_time
         self.position = (position_x, position_y)
+        self.bitfrost = bitfrost
+    """
+    def __init__(self, **args):
+        self.position = (args["position_x"], args["position_y"])
+        del args["position_x"], args["position_y"]
+        self.__dict__.update(args)
 
 class ActivityRegistry(gobject.GObject):
     __gsignals__ = {
@@ -83,24 +85,12 @@ class ActivityRegistry(gobject.GObject):
         self._service_name_to_activity_info = {}
         self._mime_type_to_activities = {}
 
-    def _convert_info_list(self, info_list):
-        result = []
-
-        for info_dict in info_list:
-            result.append(_activity_info_from_dict(info_dict))
-
-        return result
-
     def get_activities(self):
         info_list = self._registry.GetActivities()
-        return self._convert_info_list(info_list)
+        return (_activity_info_from_dict(info) for info in info_list)
 
     def _get_activities_cb(self, reply_handler, info_list):
-        result = []
-        for info_dict in info_list:
-            result.append(_activity_info_from_dict(info_dict))
-
-        reply_handler(result)
+        reply_handler(_activity_info_from_dict(info) for info in info_list)
 
     def _get_activities_error_cb(self, error_handler, e):
         if error_handler:
@@ -111,7 +101,7 @@ class ActivityRegistry(gobject.GObject):
     def get_activities_async(self, reply_handler=None, error_handler=None):
         if not reply_handler:
             logging.error('Function get_activities_async called' \
-                          'without a reply handler. Can not run.') 
+                          'without a reply handler. Can not run.')
             return
 
         self._registry.GetActivities(
@@ -120,26 +110,33 @@ class ActivityRegistry(gobject.GObject):
              error_handler=lambda e: \
                     self._get_activities_error_cb(error_handler, e))
 
+    def safe_permissions(self, bitfrost_permissions):
+        return "P_ROOT" not in bitfrost_permissions
+
     def get_activity(self, service_name):
         if self._service_name_to_activity_info.has_key(service_name):
             return self._service_name_to_activity_info[service_name]
 
         info_dict = self._registry.GetActivity(service_name)
+        
         activity_info = _activity_info_from_dict(info_dict)
-
-        self._service_name_to_activity_info[service_name] = activity_info
+        
+        #extra security precaution (to prevent dbus DOS from escalating privs):
+        # do not cache unsafe permissions
+        if self.safe_permissions(activity_info["bitfrost"]):
+            self._service_name_to_activity_info[service_name] = activity_info
         return activity_info
 
     def find_activity(self, name):
         info_list = self._registry.FindActivity(name)
-        return self._convert_info_list(info_list)
+        return (_activity_info_from_dict(info) for info in info_list)
 
     def get_activities_for_type(self, mime_type):
         if self._mime_type_to_activities.has_key(mime_type):
             return self._mime_type_to_activities[mime_type]
 
         info_list = self._registry.GetActivitiesForType(mime_type)
-        activities = self._convert_info_list(info_list)
+        activities = (_activity_info_from_dict(info) for info in info_list)
 
         self._mime_type_to_activities[mime_type] = activities
         return activities
diff --git a/src/sugar/bundle/activitybundle.py b/src/sugar/bundle/activitybundle.py
index 88ef5f1..dd620fa 100644
--- a/src/sugar/bundle/activitybundle.py
+++ b/src/sugar/bundle/activitybundle.py
@@ -23,8 +23,7 @@ import os
 import tempfile
 
 from sugar.bundle.bundle import Bundle, MalformedBundleException, \
-    AlreadyInstalledException, RegistrationException, \
-    NotInstalledException
+    AlreadyInstalledException, RegistrationException, NotInstalledException
 
 from sugar import activity
 from sugar import env
@@ -43,18 +42,22 @@ class ActivityBundle(Bundle):
     _zipped_extension = '.xo'
     _unzipped_extension = '.activity'
     _infodir = 'activity'
+    
+    _name = None
+    _icon = None
+    _bundle_id = None
+    _mime_types = None
+    _show_launcher = True
+    _activity_version = 0
+    _bitfrost_requests = frozenset()
+    
 
     def __init__(self, path):
         Bundle.__init__(self, path)
         self.activity_class = None
         self.bundle_exec = None
         
-        self._name = None
-        self._icon = None
-        self._bundle_id = None
-        self._mime_types = None
-        self._show_launcher = True
-        self._activity_version = 0
+        self._installation_time = os.stat(path).st_mtime
 
         info_file = self.get_file('activity/activity.info')
         if info_file is None:
@@ -65,7 +68,7 @@ class ActivityBundle(Bundle):
         if linfo_file:
             self._parse_linfo(linfo_file)
 
-        self.manifest = None #This should be replaced by following function
+        self.manifest = None # This should be replaced by following function
         self.read_manifest()
 
     def _raw_manifest(self):
@@ -176,7 +179,14 @@ class ActivityBundle(Bundle):
                 raise MalformedBundleException(
                     'Activity bundle %s has invalid version number %s' %
                     (self._path, version))
-
+        
+        if cp.has_option(section, "bitfrost_requests"):
+            bitfrost = cp.get(section, "bitfrost_requests")
+            #bitfrost_requests = P_SOMETHING, P_SOMETHING_ELSE, p_some garbage, P_MAL FORMED,
+            #becomes set("P_SOMETHING","P_SOMETHING_ELSE","P_MAL FORMED")
+            bitfrost = (word.strip() for word in bitfrost.split(",") if word.strip().startswith("P_"))
+            self._bitfrost_requests = set(bitfrost)
+            
     def _get_linfo_file(self):
         lang = locale.getdefaultlocale()[0]
         if not lang:
@@ -226,7 +236,7 @@ class ActivityBundle(Bundle):
     def get_installation_time(self):
         """Get a timestamp representing the time at which this activity was
         installed."""
-        return os.stat(self._path).st_mtime
+        return self._installation_time
 
     def get_bundle_id(self):
         """Get the activity bundle id"""
@@ -259,6 +269,8 @@ class ActivityBundle(Bundle):
 
         return command
 
+    def get_bitfrost_requests(self):
+        return self._bitfrost_requests
 
     def get_mime_types(self):
         """Get the MIME types supported by the activity"""
@@ -275,10 +287,10 @@ class ActivityBundle(Bundle):
             return False
 
     def need_upgrade(self):
-        """Returns True if installing this activity bundle is meaningful - 
+        """Returns True if installing this activity bundle is meaningful -
         that is, if an identical version of this activity is not
         already installed.
-        
+
         Until we have cryptographic hashes to check identity, returns
         True always. See http://dev.laptop.org/ticket/7534.""";
         return True
@@ -352,7 +364,11 @@ class ActivityBundle(Bundle):
                                             os.path.basename(info_file)))
         return install_path
 
-    def install(self):
+    def install(self, securitycheck=True):
+        if securitycheck:
+            if "P_ROOT" in self.get_bitfrost_requests():
+                raise MalformedBundleException(
+                        "No privileges to install a P_ROOT activity")
         activities_path = env.get_user_activities_path()
         act = activity.get_registry().get_activity(self._bundle_id)
         if act is not None and act.path.startswith(activities_path):
From 91ac9e1222bd54a84f8414ca7c2e712f8459eee4 Mon Sep 17 00:00:00 2001
From: Jameson Quinn <[EMAIL PROTECTED]>
Date: Wed, 6 Aug 2008 10:29:04 -0600
Subject: [PATCH] some minor pylint fixes

---
 service/bundleregistry.py |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/service/bundleregistry.py b/service/bundleregistry.py
index 5d3fec8..04adbc2 100644
--- a/service/bundleregistry.py
+++ b/service/bundleregistry.py
@@ -54,7 +54,7 @@ class BundleRegistry(gobject.GObject):
         try:
             self._load_favorites()
         except Exception, e:
-            logging.error('Error while loading favorite_activities\n%s.' \
+            logging.error('Error while loading favorite_activities\n  %s.' \
                     % traceback.format_exc())
 
         self._merge_default_favorites()
@@ -104,8 +104,8 @@ class BundleRegistry(gobject.GObject):
                 if not isinstance(first_key, basestring):
                     raise ValueError('Invalid format in %s.' % favorites_path)
 
-                first_value = favorite_bundles.values()[0]
-                if first_value is not None and not isinstance(first_value, dict):
+                first_val = favorite_bundles.values()[0]
+                if first_val is not None and not isinstance(first_val, dict):
                     raise ValueError('Invalid format in %s.' % favorites_path)
 
             self._last_defaults_mtime = float(favorites_data['defaults-mtime'])
-- 
1.5.2.5

_______________________________________________
Sugar mailing list
Sugar@lists.laptop.org
http://lists.laptop.org/listinfo/sugar

Reply via email to