diff --git a/modules/block/block.module b/modules/block/block.module
index cc1e63ba4c2283475a2a287ba762401e50ed1f5e..630555ba4c5353facdcfd6505502553f34bf7191 100644
--- a/modules/block/block.module
+++ b/modules/block/block.module
@@ -853,6 +853,17 @@ function template_preprocess_block(&$variables) {
   $variables['template_files'][] = 'block-' . $variables['block']->module . '-' . $variables['block']->delta;
 }
 
+/**
+ * Implement hook_user_role_delete().
+ *
+ * Remove deleted role from blocks that use it. 
+ */
+function block_user_role_delete($role) {
+  db_delete('block_role')
+    ->condition('rid', $role->rid)
+    ->execute();
+}
+
 /**
  * Implement hook_filter_format_delete().
  */
diff --git a/modules/filter/filter.module b/modules/filter/filter.module
index ccc7bb101daed06eccb7a98c90e3afb64b1ca3ab..71df8fcaa16497e87d56fd787838eec871650805 100644
--- a/modules/filter/filter.module
+++ b/modules/filter/filter.module
@@ -963,3 +963,15 @@ function _filter_autop($text) {
 /**
  * @} End of "Standard filters".
  */
+
+/**
+ * Implement hook_user_role_delete().
+ * 
+ * Remove deleted role from formats that use it. 
+ */
+function filter_user_role_delete($role) {
+  db_update('filter_format')
+    ->expression('roles', 'REPLACE(roles, :rid, :replacement)', array(':rid' => ',' . $role->rid, ':replacement' => ''))
+    ->condition('roles', '%,' . $role->rid . '%', 'LIKE')
+    ->execute();
+}
diff --git a/modules/simpletest/drupal_web_test_case.php b/modules/simpletest/drupal_web_test_case.php
index 8ef61367aa4120ae1a3320a5a90ab6b8414386d6..822a92a15500b8d6bf41a048d5d125067b2de041 100644
--- a/modules/simpletest/drupal_web_test_case.php
+++ b/modules/simpletest/drupal_web_test_case.php
@@ -892,26 +892,19 @@ protected function drupalCreateRole(array $permissions, $name = NULL) {
       $name = $this->randomName();
     }
 
+    // Check the all the permissions strings are valid.
     if (!$this->checkPermissions($permissions)) {
       return FALSE;
     }
 
     // Create new role.
-    db_insert('role')
-      ->fields(array('name' => $name))
-      ->execute();
-    $role = db_query('SELECT * FROM {role} WHERE name = :name', array(':name' => $name))->fetchObject();
-    $this->assertTrue($role, t('Created role of name: @name, id: @rid', array('@name' => $name, '@rid' => (isset($role->rid) ? $role->rid : t('-n/a-')))), t('Role'));
+    $role = new stdClass();
+    $role->name = $name;
+    user_role_save($role);
+    user_role_set_permissions($role->name, $permissions);
+    
+    $this->assertTrue(isset($role->rid), t('Created role of name: @name, id: @rid', array('@name' => $name, '@rid' => (isset($role->rid) ? $role->rid : t('-n/a-')))), t('Role'));
     if ($role && !empty($role->rid)) {
-      // Assign permissions to role and mark it for clean-up.
-      $query = db_insert('role_permission')->fields(array('rid', 'permission'));
-      foreach ($permissions as $permission_string) {
-        $query->values(array(
-          'rid' => $role->rid,
-          'permission' => $permission_string,
-        ));
-      }
-      $query->execute();
       $count = db_query('SELECT COUNT(*) FROM {role_permission} WHERE rid = :rid', array(':rid' => $role->rid))->fetchField();
       $this->assertTrue($count == count($permissions), t('Created permissions: @perms', array('@perms' => implode(', ', $permissions))), t('Role'));
       return $role->rid;
diff --git a/modules/system/system.install b/modules/system/system.install
index df678015aed23ccb4ef74af64addd0051a05c168..613f029be56835677e9e3622023f4057cb71e9aa 100644
--- a/modules/system/system.install
+++ b/modules/system/system.install
@@ -385,21 +385,6 @@ function system_install() {
       ->execute();
   }
 
-  $query = db_insert('role_permission')->fields(array('rid', 'permission'));
-  // Anonymous role permissions.
-  $query->values(array(
-    'rid' => DRUPAL_ANONYMOUS_RID,
-    'permission' => 'access content',
-  ));
-
-  // Authenticated role permissions.
-  foreach (array('access comments', 'access content', 'post comments', 'post comments without approval', 'view own unpublished content') as $permission) {
-    $query->values(array(
-      'rid' => DRUPAL_AUTHENTICATED_RID,
-      'permission' => $permission,
-    ));
-  }
-  $query->execute();
 
   variable_set('theme_default', 'garland');
 
diff --git a/modules/user/user.admin.inc b/modules/user/user.admin.inc
index b7f3ff4a1a7febfae831add0f0424e990a778793..99948a3579e10706e054709e2e54797e03804645 100644
--- a/modules/user/user.admin.inc
+++ b/modules/user/user.admin.inc
@@ -663,19 +663,8 @@ function user_admin_permissions($form_state, $rid = NULL) {
  */
 function user_admin_permissions_submit($form, &$form_state) {
   foreach ($form_state['values']['role_names'] as $rid => $name) {
-    $checked = array_filter($form_state['values'][$rid]);
-    // Delete existing permissions for the role. This handles "unchecking" checkboxes.
-    db_delete('role_permission')
-      ->condition('rid', $rid)
-      ->execute();
-    $query = db_insert('role_permission')->fields(array('rid', 'permission'));
-    foreach ($checked as $permission) {
-      $query->values(array(
-        'rid' => $rid,
-        'permission' => $permission,
-      ));
-    }
-    $query->execute();
+    $permissions = array_filter($form_state['values'][$rid]);
+    user_role_set_permissions($rid, $permissions);
   }
 
   drupal_set_message(t('The changes have been saved.'));
@@ -776,13 +765,13 @@ function user_admin_role() {
 function user_admin_role_validate($form, &$form_state) {
   if ($form_state['values']['name']) {
     if ($form_state['values']['op'] == t('Save role')) {
-      $existing_role = (bool) db_query_range("SELECT 1 FROM {role} WHERE name = :name AND rid <> :rid", array(':name' => $form_state['values']['name'], ':rid' => $form_state['values']['rid']), 0, 1)->fetchField();
-      if ($existing_role) {
+      $role = user_role_load($form_state['values']['name']);
+      if ($role && $role->rid != $form_state['values']['rid']) {    
         form_set_error('name', t('The role name %name already exists. Please choose another role name.', array('%name' => $form_state['values']['name'])));
       }
     }
     elseif ($form_state['values']['op'] == t('Add role')) {
-      if ((bool) db_query_range('SELECT 1 FROM {role} WHERE name = :name', array(':name' => $form_state['values']['name']), 0, 1)->fetchField()) {
+      if (user_role_load($form_state['values']['name'])) {
         form_set_error('name', t('The role name %name already exists. Please choose another role name.', array('%name' => $form_state['values']['name'])));
       }
     }
@@ -793,31 +782,17 @@ function user_admin_role_validate($form, &$form_state) {
 }
 
 function user_admin_role_submit($form, &$form_state) {
+  $role = (object)$form_state['values'];
   if ($form_state['values']['op'] == t('Save role')) {
-    db_update('role')
-      ->fields(array('name' => $form_state['values']['name']))
-      ->condition('rid', $form_state['values']['rid'])
-      ->execute();
+    user_role_save($role);
     drupal_set_message(t('The role has been renamed.'));
   }
   elseif ($form_state['values']['op'] == t('Delete role')) {
-    db_delete('role')
-      ->condition('rid', $form_state['values']['rid'])
-      ->execute();
-    db_delete('role_permission')
-      ->condition('rid', $form_state['values']['rid'])
-      ->execute();
-    // Update the users who have this role set:
-    db_delete('users_roles')
-      ->condition('rid', $form_state['values']['rid'])
-      ->execute();
-
+    user_role_delete($form_state['values']['rid']);
     drupal_set_message(t('The role has been deleted.'));
   }
   elseif ($form_state['values']['op'] == t('Add role')) {
-    db_insert('role')
-      ->fields(array('name' => $form_state['values']['name']))
-      ->execute();
+    user_role_save($role);
     drupal_set_message(t('The role has been added.'));
   }
   $form_state['redirect'] = 'admin/config/people/roles';
diff --git a/modules/user/user.api.php b/modules/user/user.api.php
index e3c706555f67ab8fc32433af6b1c13be8ddb9a81..88d4c0fa1016b2040c4571edf1c0a844f336a180 100644
--- a/modules/user/user.api.php
+++ b/modules/user/user.api.php
@@ -422,6 +422,66 @@ function hook_user_view($account) {
   }
 }
 
+/**
+ * Inform other modules that a user role has been added.
+ *
+ * Modules implementing this hook can act on the user role object when saved to
+ * the database. It's recommended that you implement this hook if your module
+ * adds additional data to user roles object. The module should save its custom
+ * additions to the database.
+ *
+ * @param $role
+ *   A user role object.
+ */
+function hook_user_role_insert($role) {
+  // Save extra fields provided by the module to user roles.
+  db_insert('my_module_table')
+    ->fields(array(
+      'rid' => $role->rid,
+      'role_description' => $role->description,
+    ))
+    ->execute();
+}
+
+/**
+ * Inform other modules that a user role has been updated.
+ *
+ * Modules implementing this hook can act on the user role object when updated.
+ * It's recommended that you implement this hook if your module adds additional
+ * data to user roles object. The module should save its custom additions to
+ * the database.
+ *
+ * @param $role
+ *   A user role object.
+ */
+function hook_user_role_update($role) {
+  // Save extra fields provided by the module to user roles.
+  db_merge('my_module_table')
+    ->key(array('rid' => $role->rid))
+    ->fields(array(
+      'role_description' => $role->description
+    ))
+    ->execute();
+}
+
+/**
+ * Inform other modules that a user role has been deleted.
+ *
+ * This hook allows you act when a user role has been deleted.
+ * If your module stores references to roles, it's recommended that you 
+ * implement this hook and delete existing instances of the deleted role
+ * in your module database tables.
+ *
+ * @param $role
+ *   The $role object being deleted.
+ */
+function hook_user_role_delete($role) {
+  // Delete existing instances of the deleted role.
+  db_delete('my_module_table')
+    ->condition('rid', $role->rid)
+    ->execute();
+}
+
 /**
  * @} End of "addtogroup hooks".
  */
diff --git a/modules/user/user.module b/modules/user/user.module
index 0b25f3e44962835cab5d64145e61e3f0660a3607..cc7c83d99bdd2e2cd904997dc3c0a0c69e44c801 100644
--- a/modules/user/user.module
+++ b/modules/user/user.module
@@ -2206,6 +2206,114 @@ function user_roles($membersonly = FALSE, $permission = NULL) {
   return array_filter($roles);
 }
 
+/**
+ * Fetch a user role from database.
+ *
+ * @param $role
+ *   A string with the role name, or an integer with the role ID.
+ * @return
+ *   A fully-loaded role object if a role with the given name or ID 
+ *   exists, FALSE otherwise.
+ */
+function user_role_load($role) {
+  $field = is_int($role) ? 'rid' : 'name';
+  return db_select('role', 'r')
+    ->fields('r')
+    ->condition($field, $role)
+    ->execute()
+    ->fetchObject();
+}
+/**
+ * Save a user role to the database.
+ *
+ * @param $role
+ *   A role object to modify or add. If $role->rid is not specified, a new
+ *   role will be created.
+ * @return
+ *   Status constant indicating if role was created or updated.
+ *   Failure to write the user role record will return FALSE. Otherwise.
+ *   SAVED_NEW or SAVED_UPDATED is returned depending on the operation 
+ *   performed.
+ */
+function user_role_save($role) {
+  if ($role->name) {
+    // Prevent leading and trailing spaces in role names.
+    $role->name = trim($role->name);
+  }
+  if (!empty($role->rid) && $role->name) {
+    $status = drupal_write_record('role', $role, 'rid');
+    module_invoke_all('user_role_update', $role);
+  }
+  else {
+    $status = drupal_write_record('role', $role);
+    module_invoke_all('user_role_insert', $role);
+  }
+  
+  return $status;
+}
+
+/**
+ * Delete a user role from database.
+ *
+ * @param $role
+ *   A string with the role name, or an integer with the role ID.
+ */
+function user_role_delete($role) {
+  $role = user_role_load($role);
+
+  db_delete('role')
+    ->condition('rid', $role->rid)
+    ->execute();
+  db_delete('role_permission')
+    ->condition('rid', $role->rid)
+    ->execute();
+  // Update the users who have this role set:
+  db_delete('users_roles')
+    ->condition('rid', $role->rid)
+    ->execute();
+    
+  // Clear the user access cache.
+  user_access(NULL, NULL, TRUE);
+    
+  module_invoke_all('user_role_delete', $role);
+}
+
+/**
+ * Assign permissions to a user role.
+ *
+ * @param $role
+ *   A string with the role name, or an integer with the role ID.
+ * @param $permissions
+ *   An array of permissions strings.
+ * @param $merge
+ *   A boolean indicating whether to add permissions or to merge 
+ *   with all existing permissions.
+ */
+function user_role_set_permissions($role, array $permissions = array(), $merge = FALSE) {
+  $role = user_role_load($role);
+  if (!$merge) {
+    // Delete existing permissions for the role.
+    db_delete('role_permission')
+      ->condition('rid', $role->rid)
+      ->execute();
+  }
+
+  // Assign the new permissions for the role.
+  foreach ($permissions as $permission_string) {
+    db_merge('role_permission')
+      ->key(array(
+        'rid' => $role->rid,
+        'permission' => $permission_string,
+      ))
+      ->execute();
+  }
+
+  // Clear the user access cache.
+  user_access(NULL, NULL, TRUE);
+
+  return TRUE;
+}
+
 /**
  * Implement hook_user_operations().
  */
diff --git a/profiles/default/default.install b/profiles/default/default.install
index 7a81aecd52349797a8c6a8eed5a15b0af086fce7..60e5d012e0ed12d09d52938a41fd8640a7229288 100644
--- a/profiles/default/default.install
+++ b/profiles/default/default.install
@@ -183,20 +183,18 @@ function default_install() {
   ))->execute();
   db_insert('taxonomy_vocabulary_node_type')->fields(array('vid' => $vid, 'type' => 'article'))->execute();
 
-  // Create a default role for site administrators.
-  $rid = db_insert('role')->fields(array('name' => 'administrator'))->execute();
+  // Enable default permissions for system roles.
+  user_role_set_permissions(DRUPAL_ANONYMOUS_RID, array('access content'));
+  user_role_set_permissions(DRUPAL_AUTHENTICATED_RID, array('access content', 'access comments', 'post comments', 'post comments without approval'));
 
+
+  // Create a default role for site administrators, with all available permissions assigned.
+  $admin_role = new stdClass();
+  $admin_role->name = 'administrator';
+  user_role_save($admin_role);
+  user_role_set_permissions($admin_role->name, array_keys(module_invoke_all('permission')));
   // Set this as the administrator role.
-  variable_set('user_admin_role', $rid);
-
-  // Assign all available permissions to this role.
-  foreach (module_invoke_all('permission') as $key => $value) {
-    db_insert('role_permission')
-      ->fields(array(
-        'rid' => $rid,
-        'permission' => $key,
-      ))->execute();
-  }
+  variable_set('user_admin_role', $admin_role->rid);
 
   // Update the menu router information.
   menu_rebuild();
diff --git a/profiles/expert/expert.install b/profiles/expert/expert.install
index bcb6cfff8d7eadb398086bf40c274e2cc347721d..4693b84b4814c073dfad1097f3295cd235f69289 100644
--- a/profiles/expert/expert.install
+++ b/profiles/expert/expert.install
@@ -66,6 +66,10 @@ function expert_install() {
     $query->values($record);
   }
   $query->execute();  
+
+  // Enable default permissions for system roles.
+  user_role_set_permissions(DRUPAL_ANONYMOUS_RID, array('access content'));
+  user_role_set_permissions(DRUPAL_AUTHENTICATED_RID, array('access content', 'access comments', 'post comments', 'post comments without approval'));
 }