Index: modules/user/user.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.admin.inc,v
retrieving revision 1.21
diff -u -p -r1.21 user.admin.inc
--- modules/user/user.admin.inc	14 Apr 2008 17:48:43 -0000	1.21
+++ modules/user/user.admin.inc	20 Apr 2008 21:06:20 -0000
@@ -500,12 +500,9 @@ function user_admin_perm($form_state, $r
     $result = db_query('SELECT r.rid, p.perm FROM {role} r LEFT JOIN {permission} p ON r.rid = p.rid ORDER BY name');
   }
 
-  // Compile role array:
-  // Add a comma at the end so when searching for a permission, we can
-  // always search for "$perm," to make sure we do not confuse
-  // permissions that are substrings of each other.
+  // Compile array of permissions for each role.
   while ($role = db_fetch_object($result)) {
-    $role_permissions[$role->rid] = $role->perm . ',';
+    $role_permissions[$role->rid] = explode(',', $role->perm);
   }
 
   // Retrieve role names for columns.
@@ -515,39 +512,49 @@ function user_admin_perm($form_state, $r
   }
 
   // Render role/permission overview:
-  $options = array();
   $hide_descriptions = !system_admin_compact_mode();
   foreach (module_list(FALSE, FALSE, TRUE) as $module) {
     if ($permissions = module_invoke($module, 'perm')) {
+      drupal_alter('perm', $permissions, $module, $rid);
       $form['permission'][] = array(
         '#value' => $module,
       );
       ksort($permissions);
-      foreach ($permissions as $perm => $description) {
-        // Account for permissions lacking a description.
-        if (is_int($perm)) {
-          $perm = $description;
-          $description = NULL;
+      foreach ($permissions as $perm => $item) {
+        if (!is_array($item)) {
+          $item = array();
+        }
+        if (!isset($item['description'])) {
+          $item['description'] = NULL;
+        }
+        if (!isset($item['denied roles'])) {
+          // By default, all permissions are denied for anonymous users.
+          $item['denied roles'] = array(DRUPAL_ANONYMOUS_RID);
         }
-        $options[$perm] = '';
         $form['permission'][$perm] = array(
           '#type' => 'item',
           '#value' => t($perm),
-          '#description' => $hide_descriptions ? $description : NULL,
+          '#description' => $hide_descriptions ? $item['description'] : NULL,
         );
         foreach ($role_names as $rid => $name) {
-          // Builds arrays for checked boxes for each role
-          if (strpos($role_permissions[$rid], $perm . ',') !== FALSE) {
-            $status[$rid][] = $perm;
+          // Build check boxes for each role
+          $checkbox = array('#type' => 'checkbox', '#title' => '', '#tree' => TRUE);
+          if (in_array($perm, $role_permissions[$rid], TRUE)) {
+            $checkbox['#default_value'] = TRUE;
+          }
+          if (in_array($rid, $item['denied roles'])) {
+            $checkbox['#disabled'] = TRUE;
+            $checkbox['#default_value'] = FALSE;
           }
+          $form['checkboxes'][$rid]['#tree'] = TRUE;
+          $form['checkboxes'][$rid][$perm] = $checkbox;
         }
       }
     }
   }
 
-  // Have to build checkboxes here after checkbox arrays are built
+  // Build list of role names.
   foreach ($role_names as $rid => $name) {
-    $form['checkboxes'][$rid] = array('#type' => 'checkboxes', '#options' => $options, '#default_value' => isset($status[$rid]) ? $status[$rid] : array());
     $form['role_names'][$rid] = array('#value' => $name, '#tree' => TRUE);
   }
   $form['submit'] = array('#type' => 'submit', '#value' => t('Save permissions'));
@@ -565,7 +572,7 @@ function user_admin_perm_submit($form, &
       db_query('DELETE FROM {permission} WHERE rid = %d', $role->rid);
       $form_state['values'][$role->rid] = array_filter($form_state['values'][$role->rid]);
       if (count($form_state['values'][$role->rid])) {
-        db_query("INSERT INTO {permission} (rid, perm) VALUES (%d, '%s')", $role->rid, implode(', ', array_keys($form_state['values'][$role->rid])));
+        db_query("INSERT INTO {permission} (rid, perm) VALUES (%d, '%s')", $role->rid, implode(',', array_keys($form_state['values'][$role->rid])));
       }
     }
   }
Index: modules/user/user.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.module,v
retrieving revision 1.903
diff -u -p -r1.903 user.module
--- modules/user/user.module	19 Apr 2008 17:10:50 -0000	1.903
+++ modules/user/user.module	20 Apr 2008 21:06:21 -0000
@@ -499,12 +499,20 @@ function user_is_blocked($name) {
  * Implementation of hook_perm().
  */
 function user_perm() {
-   return array(
-     'administer permissions' => t('Manage the permissions assigned to user roles. %warning', array('%warning' => t('Warning: Give to trusted roles only; this permission has security implications.'))),
-     'administer users' => t('Manage or block users, and manage their role assignments.'),
-     'access user profiles' => t('View profiles of users on the site, which may contain personal information.'),
-     'change own username' => t('Select a different username.'),
+  $perms = array();
+
+   $perms['administer permissions'] = array(
+     'description' => t('Manage the permissions assigned to user roles. %warning', array('%warning' => t('Warning: Give to trusted roles only; this permission has security implications.'))),
+     'denied roles' => array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID),
+   );
+   $perms['administer users'] = array(
+     'description' => t('Manage or block users, and manage their role assignments.'),
+     'denied roles' => array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID),
    );
+   $perms['access user profiles'] = array('description' => t('View profiles of users on the site, which may contain personal information.'),);
+   $perms['change own username'] = array('description' => t('Select a different username.'),);
+   
+   return $perms;
 }
 
 /**
