123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469 |
- # -*- Mode: perl; indent-tabs-mode: nil -*-
- #
- # The contents of this file are subject to the Mozilla Public
- # License Version 1.1 (the "License"); you may not use this file
- # except in compliance with the License. You may obtain a copy of
- # the License at http://www.mozilla.org/MPL/
- #
- # Software distributed under the License is distributed on an "AS
- # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- # implied. See the License for the specific language governing
- # rights and limitations under the License.
- #
- # The Original Code is the Bugzilla Bug Tracking System.
- #
- # The Initial Developer of the Original Code is Netscape Communications
- # Corporation. Portions created by Netscape are
- # Copyright (C) 1998 Netscape Communications Corporation. All
- # Rights Reserved.
- #
- # Contributor(s): Terry Weissman <terry@mozilla.org>
- # Dawn Endico <endico@mozilla.org>
- # Dan Mosedale <dmose@mozilla.org>
- # Joe Robins <jmrobins@tgix.com>
- # Jacob Steenhagen <jake@bugzilla.org>
- # J. Paul Reed <preed@sigkill.com>
- # Bradley Baetz <bbaetz@student.usyd.edu.au>
- # Joseph Heenan <joseph@heenan.me.uk>
- # Erik Stambaugh <erik@dasbistro.com>
- # Frédéric Buclin <LpSolit@gmail.com>
- # Marc Schumann <wurblzap@gmail.com>
- #
- package Bugzilla::Config::Common;
- use strict;
- use Socket;
- use Time::Zone;
- use Bugzilla::Util;
- use Bugzilla::Constants;
- use Bugzilla::Field;
- use Bugzilla::Group;
- use Bugzilla::Status;
- use base qw(Exporter);
- @Bugzilla::Config::Common::EXPORT =
- qw(check_multi check_numeric check_regexp check_url check_group
- check_sslbase check_priority check_severity check_platform
- check_opsys check_shadowdb check_urlbase check_webdotbase
- check_netmask check_user_verify_class check_image_converter
- check_mail_delivery_method check_notification check_timezone check_utf8
- check_bug_status check_smtp_auth
- check_maxattachmentsize
- );
- # Checking functions for the various values
- sub check_multi {
- my ($value, $param) = (@_);
- if ($param->{'type'} eq "s") {
- unless (scalar(grep {$_ eq $value} (@{$param->{'choices'}}))) {
- return "Invalid choice '$value' for single-select list param '$param->{'name'}'";
- }
- return "";
- }
- elsif ($param->{'type'} eq 'm' || $param->{'type'} eq 'o') {
- foreach my $chkParam (split(',', $value)) {
- unless (scalar(grep {$_ eq $chkParam} (@{$param->{'choices'}}))) {
- return "Invalid choice '$chkParam' for multi-select list param '$param->{'name'}'";
- }
- }
- return "";
- }
- else {
- return "Invalid param type '$param->{'type'}' for check_multi(); " .
- "contact your Bugzilla administrator";
- }
- }
- sub check_numeric {
- my ($value) = (@_);
- if ($value !~ /^[0-9]+$/) {
- return "must be a numeric value";
- }
- return "";
- }
- sub check_regexp {
- my ($value) = (@_);
- eval { qr/$value/ };
- return $@;
- }
- sub check_sslbase {
- my $url = shift;
- if ($url ne '') {
- if ($url !~ m#^https://([^/]+).*/$#) {
- return "must be a legal URL, that starts with https and ends with a slash.";
- }
- my $host = $1;
- # Fall back to port 443 if for some reason getservbyname() fails.
- my $port = getservbyname('https', 'tcp') || 443;
- if ($host =~ /^(.+):(\d+)$/) {
- $host = $1;
- $port = $2;
- }
- local *SOCK;
- my $proto = getprotobyname('tcp');
- socket(SOCK, PF_INET, SOCK_STREAM, $proto);
- my $iaddr = inet_aton($host) || return "The host $host cannot be resolved";
- my $sin = sockaddr_in($port, $iaddr);
- if (!connect(SOCK, $sin)) {
- return "Failed to connect to $host:$port; unable to enable SSL";
- }
- close(SOCK);
- }
- return "";
- }
- sub check_utf8 {
- my $utf8 = shift;
- # You cannot turn off the UTF-8 parameter if you've already converted
- # your tables to utf-8.
- my $dbh = Bugzilla->dbh;
- if ($dbh->isa('Bugzilla::DB::Mysql') && $dbh->bz_db_is_utf8 && !$utf8) {
- return "You cannot disable UTF-8 support, because your MySQL database"
- . " is encoded in UTF-8";
- }
- return "";
- }
- sub check_priority {
- my ($value) = (@_);
- my $legal_priorities = get_legal_field_values('priority');
- if (lsearch($legal_priorities, $value) < 0) {
- return "Must be a legal priority value: one of " .
- join(", ", @$legal_priorities);
- }
- return "";
- }
- sub check_severity {
- my ($value) = (@_);
- my $legal_severities = get_legal_field_values('bug_severity');
- if (lsearch($legal_severities, $value) < 0) {
- return "Must be a legal severity value: one of " .
- join(", ", @$legal_severities);
- }
- return "";
- }
- sub check_platform {
- my ($value) = (@_);
- my $legal_platforms = get_legal_field_values('rep_platform');
- if (lsearch(['', @$legal_platforms], $value) < 0) {
- return "Must be empty or a legal platform value: one of " .
- join(", ", @$legal_platforms);
- }
- return "";
- }
- sub check_opsys {
- my ($value) = (@_);
- my $legal_OS = get_legal_field_values('op_sys');
- if (lsearch(['', @$legal_OS], $value) < 0) {
- return "Must be empty or a legal operating system value: one of " .
- join(", ", @$legal_OS);
- }
- return "";
- }
- sub check_bug_status {
- my $bug_status = shift;
- my @closed_bug_statuses = map {$_->name} closed_bug_statuses();
- if (lsearch(\@closed_bug_statuses, $bug_status) < 0) {
- return "Must be a valid closed status: one of " . join(', ', @closed_bug_statuses);
- }
- return "";
- }
- sub check_group {
- my $group_name = shift;
- return "" unless $group_name;
- my $group = new Bugzilla::Group({'name' => $group_name});
- unless (defined $group) {
- return "Must be an existing group name";
- }
- return "";
- }
- sub check_shadowdb {
- my ($value) = (@_);
- $value = trim($value);
- if ($value eq "") {
- return "";
- }
- if (!Bugzilla->params->{'shadowdbhost'}) {
- return "You need to specify a host when using a shadow database";
- }
- # Can't test existence of this because ConnectToDatabase uses the param,
- # but we can't set this before testing....
- # This can really only be fixed after we can use the DBI more openly
- return "";
- }
- sub check_urlbase {
- my ($url) = (@_);
- if ($url && $url !~ m:^http.*/$:) {
- return "must be a legal URL, that starts with http and ends with a slash.";
- }
- return "";
- }
- sub check_url {
- my ($url) = (@_);
- return '' if $url eq ''; # Allow empty URLs
- if ($url !~ m:/$:) {
- return 'must be a legal URL, absolute or relative, ending with a slash.';
- }
- return '';
- }
- sub check_webdotbase {
- my ($value) = (@_);
- $value = trim($value);
- if ($value eq "") {
- return "";
- }
- if($value !~ /^https?:/) {
- if(! -x $value) {
- return "The file path \"$value\" is not a valid executable. Please specify the complete file path to 'dot' if you intend to generate graphs locally.";
- }
- # Check .htaccess allows access to generated images
- my $webdotdir = bz_locations()->{'webdotdir'};
- if(-e "$webdotdir/.htaccess") {
- open HTACCESS, "$webdotdir/.htaccess";
- if(! grep(/ \\\.png\$/,<HTACCESS>)) {
- return "Dependency graph images are not accessible.\nAssuming that you have not modified the file, delete $webdotdir/.htaccess and re-run checksetup.pl to rectify.\n";
- }
- close HTACCESS;
- }
- }
- return "";
- }
- sub check_netmask {
- my ($mask) = @_;
- my $res = check_numeric($mask);
- return $res if $res;
- if ($mask < 0 || $mask > 32) {
- return "an IPv4 netmask must be between 0 and 32 bits";
- }
- # Note that if we changed the netmask from anything apart from 32, then
- # existing logincookies which aren't for a single IP won't work
- # any more. We can't know which ones they are, though, so they'll just
- # take space until they're periodically cleared, later.
- return "";
- }
- sub check_user_verify_class {
- # doeditparams traverses the list of params, and for each one it checks,
- # then updates. This means that if one param checker wants to look at
- # other params, it must be below that other one. So you can't have two
- # params mutually dependent on each other.
- # This means that if someone clears the LDAP config params after setting
- # the login method as LDAP, we won't notice, but all logins will fail.
- # So don't do that.
- my ($list, $entry) = @_;
- $list || return 'You need to specify at least one authentication mechanism';
- for my $class (split /,\s*/, $list) {
- my $res = check_multi($class, $entry);
- return $res if $res;
- if ($class eq 'DB') {
- # No params
- }
- elsif ($class eq 'RADIUS') {
- eval "require Authen::Radius";
- return "Error requiring Authen::Radius: '$@'" if $@;
- return "RADIUS servername (RADIUS_server) is missing" unless Bugzilla->params->{"RADIUS_server"};
- return "RADIUS_secret is empty" unless Bugzilla->params->{"RADIUS_secret"};
- }
- elsif ($class eq 'LDAP') {
- eval "require Net::LDAP";
- return "Error requiring Net::LDAP: '$@'" if $@;
- return "LDAP servername (LDAPserver) is missing" unless Bugzilla->params->{"LDAPserver"};
- return "LDAPBaseDN is empty" unless Bugzilla->params->{"LDAPBaseDN"};
- }
- else {
- return "Unknown user_verify_class '$class' in check_user_verify_class";
- }
- }
- return "";
- }
- sub check_image_converter {
- my ($value, $hash) = @_;
- if ($value == 1){
- eval "require Image::Magick";
- return "Error requiring Image::Magick: '$@'" if $@;
- }
- return "";
- }
- sub check_mail_delivery_method {
- my $check = check_multi(@_);
- return $check if $check;
- my $mailer = shift;
- if ($mailer eq 'sendmail' && $^O =~ /MSWin32/i) {
- # look for sendmail.exe
- return "Failed to locate " . SENDMAIL_EXE
- unless -e SENDMAIL_EXE;
- }
- return "";
- }
- sub check_maxattachmentsize {
- my $check = check_numeric(@_);
- return $check if $check;
- my $size = shift;
- my $dbh = Bugzilla->dbh;
- if ($dbh->isa('Bugzilla::DB::Mysql')) {
- my (undef, $max_packet) = $dbh->selectrow_array(
- q{SHOW VARIABLES LIKE 'max\_allowed\_packet'});
- my $byte_size = $size * 1024;
- if ($max_packet < $byte_size) {
- return "You asked for a maxattachmentsize of $byte_size bytes,"
- . " but the max_allowed_packet setting in MySQL currently"
- . " only allows packets up to $max_packet bytes";
- }
- }
- return "";
- }
- sub check_notification {
- my $option = shift;
- my @current_version =
- (BUGZILLA_VERSION =~ m/^(\d+)\.(\d+)(?:(rc|\.)(\d+))?\+?$/);
- if ($current_version[1] % 2 && $option eq 'stable_branch_release') {
- return "You are currently running a development snapshot, and so your " .
- "installation is not based on a branch. If you want to be notified " .
- "about the next stable release, you should select " .
- "'latest_stable_release' instead";
- }
- return "";
- }
- sub check_timezone {
- my $tz = shift;
- unless (defined(tz_offset($tz))) {
- return "must be empty or a legal timezone name, such as PDT or JST";
- }
- return "";
- }
- sub check_smtp_auth {
- my $username = shift;
- if ($username) {
- eval "require Authen::SASL";
- return "Error requiring Authen::SASL: '$@'" if $@;
- }
- return "";
- }
- # OK, here are the parameter definitions themselves.
- #
- # Each definition is a hash with keys:
- #
- # name - name of the param
- # desc - description of the param (for editparams.cgi)
- # type - see below
- # choices - (optional) see below
- # default - default value for the param
- # checker - (optional) checking function for validating parameter entry
- # It is called with the value of the param as the first arg and a
- # reference to the param's hash as the second argument
- #
- # The type value can be one of the following:
- #
- # t -- A short text entry field (suitable for a single line)
- # p -- A short text entry field (as with type = 't'), but the string is
- # replaced by asterisks (appropriate for passwords)
- # l -- A long text field (suitable for many lines)
- # b -- A boolean value (either 1 or 0)
- # m -- A list of values, with many selectable (shows up as a select box)
- # To specify the list of values, make the 'choices' key be an array
- # reference of the valid choices. The 'default' key should be a string
- # with a list of selected values (as a comma-separated list), i.e.:
- # {
- # name => 'multiselect',
- # desc => 'A list of options, choose many',
- # type => 'm',
- # choices => [ 'a', 'b', 'c', 'd' ],
- # default => [ 'a', 'd' ],
- # checker => \&check_multi
- # }
- #
- # Here, 'a' and 'd' are the default options, and the user may pick any
- # combination of a, b, c, and d as valid options.
- #
- # &check_multi should always be used as the param verification function
- # for list (single and multiple) parameter types.
- #
- # o -- A list of values, orderable, and with many selectable (shows up as a
- # JavaScript-enhanced select box if JavaScript is enabled, and a text
- # entry field if not)
- # Set up in the same way as type m.
- #
- # s -- A list of values, with one selectable (shows up as a select box)
- # To specify the list of values, make the 'choices' key be an array
- # reference of the valid choices. The 'default' key should be one of
- # those values, i.e.:
- # {
- # name => 'singleselect',
- # desc => 'A list of options, choose one',
- # type => 's',
- # choices => [ 'a', 'b', 'c' ],
- # default => 'b',
- # checker => \&check_multi
- # }
- #
- # Here, 'b' is the default option, and 'a' and 'c' are other possible
- # options, but only one at a time!
- #
- # &check_multi should always be used as the param verification function
- # for list (single and multiple) parameter types.
- sub get_param_list {
- return;
- }
- 1;
- __END__
- =head1 NAME
- Bugzilla::Config::Common - Parameter checking functions
- =head1 DESCRIPTION
- All parameter checking functions are called with two parameters:
- =head2 Functions
- =over
- =item C<check_multi>
- Checks that a multi-valued parameter (ie types C<s>, C<o> or C<m>) satisfies
- its contraints.
- =item C<check_numeric>
- Checks that the value is a valid number
- =item C<check_regexp>
- Checks that the value is a valid regexp
- =back
|