Index: admin_templates/categories/categories_edit.tpl
===================================================================
--- admin_templates/categories/categories_edit.tpl	(revision 13168)
+++ admin_templates/categories/categories_edit.tpl	(working copy)
@@ -213,6 +213,8 @@
 			reflectCachingSettings();
 		}
 	);
+
+	disable_categories('<inp2:c_InputName name="ParentId"/>', <inp2:c_AllowedCategoriesJSON/>);
 </script>
 
 <inp2:m_include t="incs/footer"/>
\ No newline at end of file
Index: admin_templates/js/script.js
===================================================================
--- admin_templates/js/script.js	(revision 13152)
+++ admin_templates/js/script.js	(working copy)
@@ -1788,4 +1788,34 @@
 			break;
 		}
 	}
+}
+
+function disable_categories($category_dropdown_id, $allowed_categories) {
+    if ($allowed_categories === true) {
+    	return ;
+    }
+
+	var $selected_category = false;
+	var $categories = $( jq('#' + $category_dropdown_id) ).children('option');
+
+    $categories.each(
+    	function () {
+    		var $me = $(this);
+    		var $category_id = parseInt( $me.attr('value') );
+
+    		if (!in_array($category_id, $allowed_categories)) {
+    			if ($me.attr('selected')) {
+    				$selected_category = $me;
+    			}
+
+    			$me.attr('disabled', 'disabled');
+    		}
+    	}
+    );
+
+    if ($selected_category !== false && $allowed_categories.length > 0) {
+    	// when selected category became disabled -> select 1st available category
+    	$selected_category.attr('selected', '');
+    	$("option[value='" + $allowed_categories[0] + '"]', $categories).attr('selected', 'selected');
+    }
 }
\ No newline at end of file
Index: kernel/db/cat_tag_processor.php
===================================================================
--- kernel/db/cat_tag_processor.php	(revision 13168)
+++ kernel/db/cat_tag_processor.php	(working copy)
@@ -878,4 +878,32 @@
 
 			return false;
 		}
+
+		/**
+		 * Returns list of categories, that have add/edit permission for current category item type
+		 *
+		 * @param Array $params
+		 * @return string
+		 */
+		function AllowedCategoriesJSON($params)
+		{
+			if ($this->Application->RecallVar('user_id') == -1) {
+				$categories = true;
+			}
+			else {
+				$object =& $this->getObject($params);
+				/* @var $object kDBItem */
+
+				$perm_helper =& $this->Application->recallObject('PermissionsHelper');
+				/* @var $perm_helper kPermissionsHelper */
+
+				$perm_prefix = $this->Application->getUnitOption($this->Prefix, 'PermItemPrefix');
+				$categories = $perm_helper->getPermissionCategories($perm_prefix . '.' . ($object->IsNewItem() ? 'ADD' : 'MODIFY'));
+			}
+
+			$json_helper =& $this->Application->recallObject('JSONHelper');
+			/* @var $json_helper JSONHelper */
+
+			return $json_helper->encode($categories);
+		}
 	}
\ No newline at end of file
Index: units/categories/categories_tag_processor.php
===================================================================
--- units/categories/categories_tag_processor.php	(revision 13168)
+++ units/categories/categories_tag_processor.php	(working copy)
@@ -1916,4 +1916,32 @@
     	}
     	return $this->Application->ParseBlock($params);
 	}
+
+	/**
+	 * Returns list of categories, that have category add/edit permission
+	 *
+	 * @param Array $params
+	 * @return string
+	 */
+	function AllowedCategoriesJSON($params)
+	{
+		if ($this->Application->RecallVar('user_id') == -1) {
+			$categories = true;
+		}
+		else {
+			$object =& $this->getObject($params);
+			/* @var $object kDBItem */
+
+			$perm_helper =& $this->Application->recallObject('PermissionsHelper');
+			/* @var $perm_helper kPermissionsHelper */
+
+			$perm_prefix = $this->Application->getUnitOption($this->Prefix, 'PermItemPrefix');
+			$categories = $perm_helper->getPermissionCategories($perm_prefix . '.' . ($object->IsNewItem() ? 'ADD' : 'MODIFY'));
+		}
+
+		$json_helper =& $this->Application->recallObject('JSONHelper');
+		/* @var $json_helper JSONHelper */
+
+		return $json_helper->encode($categories);
+	}
 }
\ No newline at end of file
Index: units/helpers/permissions_helper.php
===================================================================
--- units/helpers/permissions_helper.php	(revision 13168)
+++ units/helpers/permissions_helper.php	(working copy)
@@ -628,6 +628,59 @@
 		}
 
 		/**
+		 * Returns categories, where given permission is set to "1"
+		 *
+		 * @param string $permission_name
+		 * @return Array
+		 */
+		function getPermissionCategories($permission_name)
+		{
+			$groups = $this->Application->RecallVar('UserGroups');
+
+			// get categories, where given permission is explicitely defined
+			$sql = 'SELECT SUM(PermissionValue), CatId
+					FROM ' . TABLE_PREFIX . 'Permissions
+					WHERE Permission = "' . $permission_name . '" AND GroupId IN (' . $groups . ') AND Type = 0
+					GROUP BY CatId';
+			$permissions = $this->Conn->GetCol($sql, 'CatId');
+
+			// get all categories along with their parent path
+			$sql = 'SELECT ParentPath, CategoryId
+					FROM ' . TABLE_PREFIX . 'Category';
+			$parent_paths = $this->Conn->GetCol($sql, 'CategoryId');
+
+			foreach ($parent_paths as $category_id => $parent_path) {
+				if (array_key_exists($category_id, $permissions)) {
+					// permission for given category is set explicitly
+					continue;
+				}
+
+				$perm_value = 0;
+				$parent_path = explode('|', substr($parent_path, 1, -1));
+				$parent_path = array_reverse($parent_path);
+				array_push($parent_path, 0);
+
+				foreach ($parent_path as $parent_category_id) {
+					if (array_key_exists($parent_category_id, $permissions)) {
+						$perm_value = $permissions[$parent_category_id] ? 1 : 0;
+						break;
+					}
+				}
+
+				$permissions[$category_id] = $perm_value;
+			}
+
+			// remove categories, where given permissions is denied
+			foreach ($permissions as $category_id => $perm_value) {
+				if (!$perm_value) {
+					unset($permissions[$category_id]);
+				}
+			}
+
+			return array_keys($permissions);
+		}
+
+		/**
 		 * Allows to check MODIFY & OWNER.MODFY +/- PENDING permission combinations on item
 		 *
 		 * @param int $owner_id user_id, that is owner of the item
