Config.pm 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. # -*- Mode: perl; indent-tabs-mode: nil -*-
  2. #
  3. # The contents of this file are subject to the Mozilla Public
  4. # License Version 1.1 (the "License"); you may not use this file
  5. # except in compliance with the License. You may obtain a copy of
  6. # the License at http://www.mozilla.org/MPL/
  7. #
  8. # Software distributed under the License is distributed on an "AS
  9. # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  10. # implied. See the License for the specific language governing
  11. # rights and limitations under the License.
  12. #
  13. # The Original Code is the Bugzilla Bug Tracking System.
  14. #
  15. # The Initial Developer of the Original Code is Netscape Communications
  16. # Corporation. Portions created by Netscape are
  17. # Copyright (C) 1998 Netscape Communications Corporation. All
  18. # Rights Reserved.
  19. #
  20. # Contributor(s): Terry Weissman <terry@mozilla.org>
  21. # Dawn Endico <endico@mozilla.org>
  22. # Dan Mosedale <dmose@mozilla.org>
  23. # Joe Robins <jmrobins@tgix.com>
  24. # Jake <jake@bugzilla.org>
  25. # J. Paul Reed <preed@sigkill.com>
  26. # Bradley Baetz <bbaetz@student.usyd.edu.au>
  27. # Christopher Aillon <christopher@aillon.com>
  28. # Erik Stambaugh <erik@dasbistro.com>
  29. # Frédéric Buclin <LpSolit@gmail.com>
  30. package Bugzilla::Config;
  31. use strict;
  32. use base qw(Exporter);
  33. use Bugzilla::Constants;
  34. use Data::Dumper;
  35. use File::Temp;
  36. # Don't export localvars by default - people should have to explicitly
  37. # ask for it, as a (probably futile) attempt to stop code using it
  38. # when it shouldn't
  39. %Bugzilla::Config::EXPORT_TAGS =
  40. (
  41. admin => [qw(update_params SetParam write_params)],
  42. );
  43. Exporter::export_ok_tags('admin');
  44. use vars qw(@param_list);
  45. # INITIALISATION CODE
  46. # Perl throws a warning if we use bz_locations() directly after do.
  47. our %params;
  48. # Load in the param definitions
  49. sub _load_params {
  50. my $panels = param_panels();
  51. foreach my $panel (keys %$panels) {
  52. my $module = $panels->{$panel};
  53. eval("require $module") || die $@;
  54. my @new_param_list = "$module"->get_param_list();
  55. foreach my $item (@new_param_list) {
  56. $params{$item->{'name'}} = $item;
  57. }
  58. push(@param_list, @new_param_list);
  59. }
  60. }
  61. # END INIT CODE
  62. # Subroutines go here
  63. sub param_panels {
  64. my $param_panels = {};
  65. my $libpath = bz_locations()->{'libpath'};
  66. foreach my $item ((glob "$libpath/Bugzilla/Config/*.pm")) {
  67. $item =~ m#/([^/]+)\.pm$#;
  68. my $module = $1;
  69. $param_panels->{$module} = "Bugzilla::Config::$module" unless $module eq 'Common';
  70. }
  71. # Now check for any hooked params
  72. Bugzilla::Hook::process('config', { config => $param_panels });
  73. return $param_panels;
  74. }
  75. sub SetParam {
  76. my ($name, $value) = @_;
  77. _load_params unless %params;
  78. die "Unknown param $name" unless (exists $params{$name});
  79. my $entry = $params{$name};
  80. # sanity check the value
  81. # XXX - This runs the checks. Which would be good, except that
  82. # check_shadowdb creates the database as a side effect, and so the
  83. # checker fails the second time around...
  84. if ($name ne 'shadowdb' && exists $entry->{'checker'}) {
  85. my $err = $entry->{'checker'}->($value, $entry);
  86. die "Param $name is not valid: $err" unless $err eq '';
  87. }
  88. Bugzilla->params->{$name} = $value;
  89. }
  90. sub update_params {
  91. my ($params) = @_;
  92. my $answer = Bugzilla->installation_answers;
  93. my $param = read_param_file();
  94. # If we didn't return any param values, then this is a new installation.
  95. my $new_install = !(keys %$param);
  96. # --- UPDATE OLD PARAMS ---
  97. # Old Bugzilla versions stored the version number in the params file
  98. # We don't want it, so get rid of it
  99. delete $param->{'version'};
  100. # Change from usebrowserinfo to defaultplatform/defaultopsys combo
  101. if (exists $param->{'usebrowserinfo'}) {
  102. if (!$param->{'usebrowserinfo'}) {
  103. if (!exists $param->{'defaultplatform'}) {
  104. $param->{'defaultplatform'} = 'Other';
  105. }
  106. if (!exists $param->{'defaultopsys'}) {
  107. $param->{'defaultopsys'} = 'Other';
  108. }
  109. }
  110. delete $param->{'usebrowserinfo'};
  111. }
  112. # Change from a boolean for quips to multi-state
  113. if (exists $param->{'usequip'} && !exists $param->{'enablequips'}) {
  114. $param->{'enablequips'} = $param->{'usequip'} ? 'on' : 'off';
  115. delete $param->{'usequip'};
  116. }
  117. # Change from old product groups to controls for group_control_map
  118. # 2002-10-14 bug 147275 bugreport@peshkin.net
  119. if (exists $param->{'usebuggroups'} &&
  120. !exists $param->{'makeproductgroups'})
  121. {
  122. $param->{'makeproductgroups'} = $param->{'usebuggroups'};
  123. }
  124. if (exists $param->{'usebuggroupsentry'}
  125. && !exists $param->{'useentrygroupdefault'}) {
  126. $param->{'useentrygroupdefault'} = $param->{'usebuggroupsentry'};
  127. }
  128. # Modularise auth code
  129. if (exists $param->{'useLDAP'} && !exists $param->{'loginmethod'}) {
  130. $param->{'loginmethod'} = $param->{'useLDAP'} ? "LDAP" : "DB";
  131. }
  132. # set verify method to whatever loginmethod was
  133. if (exists $param->{'loginmethod'}
  134. && !exists $param->{'user_verify_class'})
  135. {
  136. $param->{'user_verify_class'} = $param->{'loginmethod'};
  137. delete $param->{'loginmethod'};
  138. }
  139. # Remove quip-display control from parameters
  140. # and give it to users via User Settings (Bug 41972)
  141. if ( exists $param->{'enablequips'}
  142. && !exists $param->{'quip_list_entry_control'})
  143. {
  144. my $new_value;
  145. ($param->{'enablequips'} eq 'on') && do {$new_value = 'open';};
  146. ($param->{'enablequips'} eq 'approved') && do {$new_value = 'moderated';};
  147. ($param->{'enablequips'} eq 'frozen') && do {$new_value = 'closed';};
  148. ($param->{'enablequips'} eq 'off') && do {$new_value = 'closed';};
  149. $param->{'quip_list_entry_control'} = $new_value;
  150. delete $param->{'enablequips'};
  151. }
  152. # Old mail_delivery_method choices contained no uppercase characters
  153. if (exists $param->{'mail_delivery_method'}
  154. && $param->{'mail_delivery_method'} !~ /[A-Z]/) {
  155. my $method = $param->{'mail_delivery_method'};
  156. my %translation = (
  157. 'sendmail' => 'Sendmail',
  158. 'smtp' => 'SMTP',
  159. 'qmail' => 'Qmail',
  160. 'testfile' => 'Test',
  161. 'none' => 'None');
  162. $param->{'mail_delivery_method'} = $translation{$method};
  163. }
  164. # --- DEFAULTS FOR NEW PARAMS ---
  165. _load_params unless %params;
  166. foreach my $item (@param_list) {
  167. my $name = $item->{'name'};
  168. unless (exists $param->{$name}) {
  169. print "New parameter: $name\n" unless $new_install;
  170. $param->{$name} = $answer->{$name} || $item->{'default'};
  171. }
  172. }
  173. $param->{'utf8'} = 1 if $new_install;
  174. # --- REMOVE OLD PARAMS ---
  175. my %oldparams;
  176. # Remove any old params, put them in old-params.txt
  177. foreach my $item (keys %$param) {
  178. if (!grep($_ eq $item, map ($_->{'name'}, @param_list))) {
  179. $oldparams{$item} = $param->{$item};
  180. delete $param->{$item};
  181. }
  182. }
  183. if (scalar(keys %oldparams)) {
  184. my $op_file = new IO::File('old-params.txt', '>>', 0600)
  185. || die "old-params.txt: $!";
  186. print "The following parameters are no longer used in Bugzilla,",
  187. " and so have been\nmoved from your parameters file into",
  188. " old-params.txt:\n";
  189. local $Data::Dumper::Terse = 1;
  190. local $Data::Dumper::Indent = 0;
  191. my $comma = "";
  192. foreach my $item (keys %oldparams) {
  193. print $op_file "\n\n$item:\n" . Data::Dumper->Dump([$oldparams{$item}]) . "\n";
  194. print "${comma}$item";
  195. $comma = ", ";
  196. }
  197. print "\n";
  198. $op_file->close;
  199. }
  200. if (ON_WINDOWS && !-e SENDMAIL_EXE
  201. && $param->{'mail_delivery_method'} eq 'Sendmail')
  202. {
  203. my $smtp = $answer->{'SMTP_SERVER'};
  204. if (!$smtp) {
  205. print "\nBugzilla requires an SMTP server to function on",
  206. " Windows.\nPlease enter your SMTP server's hostname: ";
  207. $smtp = <STDIN>;
  208. chomp $smtp;
  209. if ($smtp) {
  210. $param->{'smtpserver'} = $smtp;
  211. }
  212. else {
  213. print "\nWarning: No SMTP Server provided, defaulting to",
  214. " localhost\n";
  215. }
  216. }
  217. $param->{'mail_delivery_method'} = 'SMTP';
  218. }
  219. write_params($param);
  220. # Return deleted params and values so that checksetup.pl has a chance
  221. # to convert old params to new data.
  222. return %oldparams;
  223. }
  224. sub write_params {
  225. my ($param_data) = @_;
  226. $param_data ||= Bugzilla->params;
  227. my $datadir = bz_locations()->{'datadir'};
  228. my $param_file = "$datadir/params";
  229. local $Data::Dumper::Sortkeys = 1;
  230. my ($fh, $tmpname) = File::Temp::tempfile('params.XXXXX',
  231. DIR => $datadir );
  232. print $fh (Data::Dumper->Dump([$param_data], ['*param']))
  233. || die "Can't write param file: $!";
  234. close $fh;
  235. rename $tmpname, $param_file
  236. or die "Can't rename $tmpname to $param_file: $!";
  237. ChmodDataFile($param_file, 0666);
  238. # And now we have to reset the params cache so that Bugzilla will re-read
  239. # them.
  240. delete Bugzilla->request_cache->{params};
  241. }
  242. # Some files in the data directory must be world readable if and only if
  243. # we don't have a webserver group. Call this function to do this.
  244. # This will become a private function once all the datafile handling stuff
  245. # moves into this package
  246. # This sub is not perldoc'd for that reason - noone should know about it
  247. sub ChmodDataFile {
  248. my ($file, $mask) = @_;
  249. my $perm = 0770;
  250. if ((stat(bz_locations()->{'datadir'}))[2] & 0002) {
  251. $perm = 0777;
  252. }
  253. $perm = $perm & $mask;
  254. chmod $perm,$file;
  255. }
  256. sub read_param_file {
  257. my %params;
  258. my $datadir = bz_locations()->{'datadir'};
  259. if (-e "$datadir/params") {
  260. # Note that checksetup.pl sets file permissions on '$datadir/params'
  261. # Using Safe mode is _not_ a guarantee of safety if someone does
  262. # manage to write to the file. However, it won't hurt...
  263. # See bug 165144 for not needing to eval this at all
  264. my $s = new Safe;
  265. $s->rdo("$datadir/params");
  266. die "Error reading $datadir/params: $!" if $!;
  267. die "Error evaluating $datadir/params: $@" if $@;
  268. # Now read the param back out from the sandbox
  269. %params = %{$s->varglob('param')};
  270. }
  271. elsif ($ENV{'SERVER_SOFTWARE'}) {
  272. # We're in a CGI, but the params file doesn't exist. We can't
  273. # Template Toolkit, or even install_string, since checksetup
  274. # might not have thrown an error. Bugzilla::CGI->new
  275. # hasn't even been called yet, so we manually use CGI::Carp here
  276. # so that the user sees the error.
  277. require CGI::Carp;
  278. CGI::Carp->import('fatalsToBrowser');
  279. die "The $datadir/params file does not exist."
  280. . ' You probably need to run checksetup.pl.',
  281. }
  282. return \%params;
  283. }
  284. 1;
  285. __END__
  286. =head1 NAME
  287. Bugzilla::Config - Configuration parameters for Bugzilla
  288. =head1 SYNOPSIS
  289. # Administration functions
  290. use Bugzilla::Config qw(:admin);
  291. update_params();
  292. SetParam($param, $value);
  293. write_params();
  294. =head1 DESCRIPTION
  295. This package contains ways to access Bugzilla configuration parameters.
  296. =head1 FUNCTIONS
  297. =head2 Parameters
  298. Parameters can be set, retrieved, and updated.
  299. =over 4
  300. =item C<SetParam($name, $value)>
  301. Sets the param named $name to $value. Values are checked using the checker
  302. function for the given param if one exists.
  303. =item C<update_params()>
  304. Updates the parameters, by transitioning old params to new formats, setting
  305. defaults for new params, and removing obsolete ones. Used by F<checksetup.pl>
  306. in the process of an installation or upgrade.
  307. Prints out information about what it's doing, if it makes any changes.
  308. May prompt the user for input, if certain required parameters are not
  309. specified.
  310. =item C<write_params($params)>
  311. Description: Writes the parameters to disk.
  312. Params: C<$params> (optional) - A hashref to write to the disk
  313. instead of C<Bugzilla->params>. Used only by
  314. C<update_params>.
  315. Returns: nothing
  316. =item C<read_param_file()>
  317. Description: Most callers should never need this. This is used
  318. by C<Bugzilla->params> to directly read C<$datadir/params>
  319. and load it into memory. Use C<Bugzilla->params> instead.
  320. Params: none
  321. Returns: A hashref containing the current params in C<$datadir/params>.
  322. =back