]> git.ipfire.org Git - thirdparty/bugzilla.git/commitdiff
Bug 287109: [SECURITY] Names of private products/components can be exposed on certain...
authormkanat%kerio.com <>
Thu, 12 May 2005 09:07:09 +0000 (09:07 +0000)
committermkanat%kerio.com <>
Thu, 12 May 2005 09:07:09 +0000 (09:07 +0000)
Patch By Frederic Buclin <LpSolit@gmail.com> r=myk, r=joel, a=justdave

enter_bug.cgi
globals.pl
post_bug.cgi
process_bug.cgi
reports.cgi
template/en/default/global/user-error.html.tmpl

index 924977a3ee7c22bc6bbd2282bd3b609ced444341..f3437b7ed0d187040757e1f82f9283fc1de569bd 100755 (executable)
@@ -292,10 +292,7 @@ if ($cloned_bug_id) {
 
 # We need to check and make sure
 # that the user has permission to enter a bug against this product.
-if(!CanEnterProduct($product))
-{
-    ThrowUserError("entry_access_denied", { product => $product});         
-}
+CanEnterProductOrWarn($product);
 
 GetVersionTable();
 
index d0e819f02497f58ec6478e2c6a3bdc02b16e1bcf..009f93ee94f0e8b3c6fe858b099482610fb19634 100644 (file)
@@ -436,12 +436,16 @@ sub IsInClassification {
     }
 }
 
-#
-# This function determines if a user can enter bugs in the named
-# product.
+# This function determines whether or not a user can enter
+# bugs into the named product.
 sub CanEnterProduct {
-    my ($productname) = @_;
+    my ($productname, $verbose) = @_;
     my $dbh = Bugzilla->dbh;
+
+    return unless defined($productname);
+    trick_taint($productname);
+
+    # First check whether or not the user has access to that product.
     my $query = "SELECT group_id IS NULL " .
                 "FROM products " .
                 "LEFT JOIN group_control_map " .
@@ -451,13 +455,53 @@ sub CanEnterProduct {
         $query .= "AND group_id NOT IN(" . 
                    join(',', values(%{Bugzilla->user->groups})) . ") ";
     }
-    $query .= "WHERE products.name = " . SqlQuote($productname) . " " .
+    $query .= "WHERE products.name = ? " .
               $dbh->sql_limit(1);
-    PushGlobalSQLState();
-    SendSQL($query);
-    my ($ret) = FetchSQLData();
-    PopGlobalSQLState();
-    return ($ret);
+
+    my $has_access = $dbh->selectrow_array($query, undef, $productname);
+    if (!$has_access) {
+        # Do we require the exact reason why we cannot enter
+        # bugs into that product? Returning -1 explicitely
+        # means the user has no access to the product or the
+        # product does not exist.
+        return (defined($verbose)) ? -1 : 0;
+    }
+
+    # Check if the product is open for new bugs and has
+    # at least one component.
+    my $allow_new_bugs =
+        $dbh->selectrow_array("SELECT CASE WHEN disallownew = 0 THEN 1 ELSE 0 END
+                               FROM products INNER JOIN components
+                               ON components.product_id = products.id
+                               WHERE products.name = ? " .
+                               $dbh->sql_limit(1),
+                               undef, $productname);
+
+    # Return 1 if the user can enter bugs into that product;
+    # return 0 if the product is closed for new bug entry;
+    # return undef if the product has no component.
+    return $allow_new_bugs;
+}
+
+# Call CanEnterProduct() and display an error message
+# if the user cannot enter bugs into that product.
+sub CanEnterProductOrWarn {
+    my ($product) = @_;
+
+    if (!defined($product)) {
+        ThrowUserError("no_products");
+    }
+    my $status = CanEnterProduct($product, 1);
+    trick_taint($product);
+
+    if (!defined($status)) {
+        ThrowUserError("no_components", { product => $product});
+    } elsif (!$status) {
+        ThrowUserError("product_disabled", { product => $product});
+    } elsif ($status < 0) {
+        ThrowUserError("entry_access_denied", { product => $product});
+    }
+    return $status;
 }
 
 sub GetEnterableProducts {
index 9a48604094788685c5537ab9cdd2602a289b1a88..b9d63b3fe9e7b9535fa3b8ede06e4605d77c6d1b 100755 (executable)
@@ -79,11 +79,10 @@ $template->process($format->{'template'}, $vars, \$comment)
 ValidateComment($comment);
 
 # Check that the product exists and that the user
-# is allowed to submit bugs in this product.
+# is allowed to enter bugs into this product.
 my $product = $cgi->param('product');
-if (!CanEnterProduct($product)) {
-    ThrowUserError("entry_access_denied", {product => $product});
-}
+CanEnterProductOrWarn($product);
+
 my $product_id = get_product_id($product);
 
 # Set cookies
index 451613e29042b99649690c68de03914ac126d875..c000e3a4a08553503395727a4f45168be9b192c3 100755 (executable)
@@ -60,7 +60,8 @@ use Bugzilla::FlagType;
 
 # Shut up misguided -w warnings about "used only once":
 
-use vars qw(%versions
+use vars qw(@legal_product
+          %versions
           %components
           %legal_opsys
           %legal_platform
@@ -268,9 +269,26 @@ if (((defined $cgi->param('id') && $cgi->param('product') ne $oldproduct)
         $vars->{'privs'} = $PrivilegesRequired;
         ThrowUserError("illegal_change", $vars);
     }
-    CheckFormField($cgi, 'product', \@::legal_product);
+
     my $prod = $cgi->param('product');
+    trick_taint($prod);
+
+    # If at least one bug does not belong to the product we are
+    # moving to, we have to check whether or not the user is
+    # allowed to enter bugs into that product.
+    # Note that this check must be done early to avoid the leakage
+    # of component, version and target milestone names.
+    my $check_can_enter =
+        $dbh->selectrow_array("SELECT 1 FROM bugs
+                               INNER JOIN products
+                               ON bugs.product_id = products.id
+                               WHERE products.name != ?
+                               AND bugs.bug_id IN
+                               (" . join(',', @idlist) . ") " .
+                               $dbh->sql_limit(1),
+                               undef, $prod);
+
+    if ($check_can_enter) { CanEnterProductOrWarn($prod) }
 
     # note that when this script is called from buglist.cgi (rather
     # than show_bug.cgi), it's possible that the product will be changed
@@ -755,6 +773,7 @@ if ($cgi->param('component') ne $cgi->param('dontchange')) {
                                {name => $cgi->param('component'),
                                 product => $cgi->param('product')});
     
+    $cgi->param('component_id', $comp_id);
     DoComma();
     $::query .= "component_id = $comp_id";
 }
@@ -1164,17 +1183,6 @@ foreach my $id (@idlist) {
             "group_control_map AS oldcontrolmap READ",
             "group_control_map AS newcontrolmap READ",
             "group_control_map READ", "email_setting READ");
-    # Fun hack.  @::log_columns only contains the component_id,
-    # not the name (since bug 43600 got fixed).  So, we need to have
-    # this id ready for the loop below, otherwise anybody can
-    # change the component of a bug (we checked product above).
-    # http://bugzilla.mozilla.org/show_bug.cgi?id=180545
-    my $product_id = get_product_id($cgi->param('product'));
-    
-    if ($cgi->param('component') ne $cgi->param('dontchange')) {
-        $cgi->param('component_id',
-                    get_component_id($product_id, $cgi->param('component')));
-    }
 
     # It may sound crazy to set %formhash for each bug as $cgi->param()
     # will not change, but %formhash is modified below and we prefer
@@ -1258,12 +1266,6 @@ foreach my $id (@idlist) {
                       { product => $oldhash{'product'} });
     }
 
-    if ($cgi->param('product') ne $cgi->param('dontchange')
-        && $cgi->param('product') ne $oldhash{'product'}
-        && !CanEnterProduct($cgi->param('product'))) {
-        ThrowUserError("entry_access_denied",
-                       { product => $cgi->param('product') });
-    }
     if ($requiremilestone) {
         # musthavemilestoneonaccept applies only if at least two
         # target milestones are defined for the current product.
index a3e2c740e0e1f5d2a9814917ec1960eb9bd7485d..c5314b33e79161fb959ec538382a1d84da51552e 100755 (executable)
@@ -85,9 +85,7 @@ if (! defined $cgi->param('product')) {
 
     # We don't want people to be able to view
     # reports for products they don't have permissions for...
-    if (($product ne '-All-') && (!CanEnterProduct($product))) {
-        ThrowUserError("report_access_denied");
-    }
+    if ($product ne '-All-') { CanEnterProductOrWarn($product) }
           
     # We've checked that the product exists, and that the user can see it
     # This means that is OK to detaint
index b7cefa9a3144c5af43a683356549b1e175d96e87..f2ccb1497a079dd77c862f900b6f2e9eb749b01b 100644 (file)
     Patches cannot be more than [% Param('maxpatchsize') %] KB in size.
     Try breaking your patch into several pieces.
 
+  [% ELSIF error == "product_disabled" %]
+    [% title = BLOCK %]Product closed for [% terms.Bugs %] Entry[% END %]
+    Sorry, entering [% terms.bugs %] into
+    product <em>[% product FILTER html %]</em> has been disabled.
+
   [% ELSIF error == "product_edit_denied" %]
     [% title = "Product Edit Access Denied" %]
     You are not permitted to edit [% terms.bugs %] in product