Localconfig.pm 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  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 Initial Developer of the Original Code is Everything Solved.
  14. # Portions created by Everything Solved are Copyright (C) 2006
  15. # Everything Solved. All Rights Reserved.
  16. #
  17. # The Original Code is the Bugzilla Bug Tracking System.
  18. #
  19. # Contributor(s): Max Kanat-Alexander <mkanat@bugzilla.org>
  20. package Bugzilla::Install::Localconfig;
  21. # NOTE: This package may "use" any modules that it likes. However,
  22. # all functions in this package should assume that:
  23. #
  24. # * The data/ directory does not exist.
  25. # * Templates are not available.
  26. # * Files do not have the correct permissions
  27. # * The database is not up to date
  28. use strict;
  29. use Bugzilla::Constants;
  30. use Bugzilla::Install::Util qw(bin_loc);
  31. use Bugzilla::Util qw(generate_random_password);
  32. use Data::Dumper;
  33. use File::Basename qw(dirname);
  34. use IO::File;
  35. use Safe;
  36. use base qw(Exporter);
  37. our @EXPORT_OK = qw(
  38. read_localconfig
  39. update_localconfig
  40. );
  41. use constant LOCALCONFIG_VARS => (
  42. {
  43. name => 'create_htaccess',
  44. default => 1,
  45. desc => <<EOT
  46. # If you are using Apache as your web server, Bugzilla can create .htaccess
  47. # files for you that will instruct Apache not to serve files that shouldn't
  48. # be accessed from the web browser (like your local configuration data and non-cgi
  49. # executable files). For this to work, the directory your Bugzilla
  50. # installation is in must be within the jurisdiction of a <Directory> block
  51. # in the httpd.conf file that has 'AllowOverride Limit' in it. If it has
  52. # 'AllowOverride All' or other options with Limit, that's fine.
  53. # (Older Apache installations may use an access.conf file to store these
  54. # <Directory> blocks.)
  55. # If this is set to 1, Bugzilla will create these files if they don't exist.
  56. # If this is set to 0, Bugzilla will not create these files.
  57. EOT
  58. },
  59. {
  60. name => 'webservergroup',
  61. default => ON_WINDOWS ? '' : 'apache',
  62. desc => q{# This is the group your web server runs as.
  63. # If you have a Windows box, ignore this setting.
  64. # If you do not have access to the group your web server runs under,
  65. # set this to "". If you do set this to "", then your Bugzilla installation
  66. # will be _VERY_ insecure, because some files will be world readable/writable,
  67. # and so anyone who can get local access to your machine can do whatever they
  68. # want. You should only have this set to "" if this is a testing installation
  69. # and you cannot set this up any other way. YOU HAVE BEEN WARNED!
  70. # If you set this to anything other than "", you will need to run checksetup.pl
  71. # as} . ROOT_USER . qq{, or as a user who is a member of the specified group.\n}
  72. },
  73. {
  74. name => 'db_driver',
  75. default => 'mysql',
  76. desc => <<EOT
  77. # What SQL database to use. Default is mysql. List of supported databases
  78. # can be obtained by listing Bugzilla/DB directory - every module corresponds
  79. # to one supported database and the name corresponds to a driver name.
  80. EOT
  81. },
  82. {
  83. name => 'db_host',
  84. default => 'localhost',
  85. desc =>
  86. "# The DNS name of the host that the database server runs on.\n"
  87. },
  88. {
  89. name => 'db_name',
  90. default => 'bugs',
  91. desc => "# The name of the database\n"
  92. },
  93. {
  94. name => 'db_user',
  95. default => 'bugs',
  96. desc => "# Who we connect to the database as.\n"
  97. },
  98. {
  99. name => 'db_pass',
  100. default => '',
  101. desc => <<EOT
  102. # Enter your database password here. It's normally advisable to specify
  103. # a password for your bugzilla database user.
  104. # If you use apostrophe (') or a backslash (\\) in your password, you'll
  105. # need to escape it by preceding it with a '\\' character. (\\') or (\\)
  106. # (Far simpler just not to use those characters.)
  107. EOT
  108. },
  109. {
  110. name => 'db_port',
  111. default => 0,
  112. desc => <<EOT
  113. # Sometimes the database server is running on a non-standard port. If that's
  114. # the case for your database server, set this to the port number that your
  115. # database server is running on. Setting this to 0 means "use the default
  116. # port for my database server."
  117. EOT
  118. },
  119. {
  120. name => 'db_sock',
  121. default => '',
  122. desc => <<EOT
  123. # MySQL Only: Enter a path to the unix socket for MySQL. If this is
  124. # blank, then MySQL's compiled-in default will be used. You probably
  125. # want that.
  126. EOT
  127. },
  128. {
  129. name => 'db_check',
  130. default => 1,
  131. desc => <<EOT
  132. # Should checksetup.pl try to verify that your database setup is correct?
  133. # (with some combinations of database servers/Perl modules/moonphase this
  134. # doesn't work)
  135. EOT
  136. },
  137. {
  138. name => 'index_html',
  139. default => 0,
  140. desc => <<EOT
  141. # With the introduction of a configurable index page using the
  142. # template toolkit, Bugzilla's main index page is now index.cgi.
  143. # Most web servers will allow you to use index.cgi as a directory
  144. # index, and many come preconfigured that way, but if yours doesn't
  145. # then you'll need an index.html file that provides redirection
  146. # to index.cgi. Setting \$index_html to 1 below will allow
  147. # checksetup.pl to create one for you if it doesn't exist.
  148. # NOTE: checksetup.pl will not replace an existing file, so if you
  149. # wish to have checksetup.pl create one for you, you must
  150. # make sure that index.html doesn't already exist
  151. EOT
  152. },
  153. {
  154. name => 'cvsbin',
  155. default => \&_get_default_cvsbin,
  156. desc => <<EOT
  157. # For some optional functions of Bugzilla (such as the pretty-print patch
  158. # viewer), we need the cvs binary to access files and revisions.
  159. # Because it's possible that this program is not in your path, you can specify
  160. # its location here. Please specify the full path to the executable.
  161. EOT
  162. },
  163. {
  164. name => 'interdiffbin',
  165. default => \&_get_default_interdiffbin,
  166. desc => <<EOT
  167. # For some optional functions of Bugzilla (such as the pretty-print patch
  168. # viewer), we need the interdiff binary to make diffs between two patches.
  169. # Because it's possible that this program is not in your path, you can specify
  170. # its location here. Please specify the full path to the executable.
  171. EOT
  172. },
  173. {
  174. name => 'diffpath',
  175. default => \&_get_default_diffpath,
  176. desc => <<EOT
  177. # The interdiff feature needs diff, so we have to have that path.
  178. # Please specify the directory name only; do not use trailing slash.
  179. EOT
  180. },
  181. {
  182. name => 'site_wide_secret',
  183. # 64 characters is roughly the equivalent of a 384-bit key, which
  184. # is larger than anybody would ever be able to brute-force.
  185. default => sub { generate_random_password(64) },
  186. desc => <<EOT
  187. # This secret key is used by your installation for the creation and
  188. # validation of encrypted tokens to prevent unsolicited changes,
  189. # such as bug changes. A random string is generated by default.
  190. # It's very important that this key is kept secret. It also must be
  191. # very long.
  192. EOT
  193. },
  194. );
  195. use constant OLD_LOCALCONFIG_VARS => qw(
  196. mysqlpath
  197. contenttypes
  198. pages
  199. severities platforms opsys priorities
  200. );
  201. sub read_localconfig {
  202. my ($include_deprecated) = @_;
  203. my $filename = bz_locations()->{'localconfig'};
  204. my %localconfig;
  205. if (-e $filename) {
  206. my $s = new Safe;
  207. # Some people like to store their database password in another file.
  208. $s->permit('dofile');
  209. $s->rdo($filename);
  210. if ($@ || $!) {
  211. my $err_msg = $@ ? $@ : $!;
  212. die <<EOT;
  213. An error has occurred while reading your 'localconfig' file. The text of
  214. the error message is:
  215. $err_msg
  216. Please fix the error in your 'localconfig' file. Alternately, rename your
  217. 'localconfig' file, rerun checksetup.pl, and re-enter your answers.
  218. \$ mv -f localconfig localconfig.old
  219. \$ ./checksetup.pl
  220. EOT
  221. }
  222. my @vars = map($_->{name}, LOCALCONFIG_VARS);
  223. push(@vars, OLD_LOCALCONFIG_VARS) if $include_deprecated;
  224. foreach my $var (@vars) {
  225. my $glob = $s->varglob($var);
  226. # We can't get the type of a variable out of a Safe automatically.
  227. # We can only get the glob itself. So we figure out its type this
  228. # way, by trying first a scalar, then an array, then a hash.
  229. #
  230. # The interesting thing is that this converts all deprecated
  231. # array or hash vars into hashrefs or arrayrefs, but that's
  232. # fine since as I write this all modern localconfig vars are
  233. # actually scalars.
  234. if (defined $$glob) {
  235. $localconfig{$var} = $$glob;
  236. }
  237. elsif (defined @$glob) {
  238. $localconfig{$var} = \@$glob;
  239. }
  240. elsif (defined %$glob) {
  241. $localconfig{$var} = \%$glob;
  242. }
  243. }
  244. }
  245. return \%localconfig;
  246. }
  247. #
  248. # This is quite tricky. But fun!
  249. #
  250. # First we read the file 'localconfig'. Then we check if the variables we
  251. # need are defined. If not, we will append the new settings to
  252. # localconfig, instruct the user to check them, and stop.
  253. #
  254. # Why do it this way?
  255. #
  256. # Assume we will enhance Bugzilla and eventually more local configuration
  257. # stuff arises on the horizon.
  258. #
  259. # But the file 'localconfig' is not in the Bugzilla CVS or tarfile. You
  260. # know, we never want to overwrite your own version of 'localconfig', so
  261. # we can't put it into the CVS/tarfile, can we?
  262. #
  263. # Now, when we need a new variable, we simply add the necessary stuff to
  264. # LOCALCONFIG_VARS. When the user gets the new version of Bugzilla from CVS and
  265. # runs checksetup, it finds out "Oh, there is something new". Then it adds
  266. # some default value to the user's local setup and informs the user to
  267. # check that to see if it is what the user wants.
  268. #
  269. # Cute, ey?
  270. #
  271. sub update_localconfig {
  272. my ($params) = @_;
  273. my $output = $params->{output} || 0;
  274. my $answer = Bugzilla->installation_answers;
  275. my $localconfig = read_localconfig('include deprecated');
  276. my @new_vars;
  277. foreach my $var (LOCALCONFIG_VARS) {
  278. my $name = $var->{name};
  279. my $value = $localconfig->{$name};
  280. # Regenerate site_wide_secret if it was made by our old, weak
  281. # generate_random_password. Previously we used to generate
  282. # a 256-character string for site_wide_secret.
  283. $value = undef if ($name eq 'site_wide_secret' and defined $value
  284. and length($value) == 256);
  285. if (!defined $value) {
  286. push(@new_vars, $name);
  287. $var->{default} = &{$var->{default}} if ref($var->{default}) eq 'CODE';
  288. $localconfig->{$name} = $answer->{$name} || $var->{default};
  289. }
  290. }
  291. my @old_vars;
  292. foreach my $name (OLD_LOCALCONFIG_VARS) {
  293. push(@old_vars, $name) if defined $localconfig->{$name};
  294. }
  295. if (!$localconfig->{'interdiffbin'} && $output) {
  296. print <<EOT
  297. OPTIONAL NOTE: If you want to be able to use the 'difference between two
  298. patches' feature of Bugzilla (which requires the PatchReader Perl module
  299. as well), you should install patchutils from:
  300. http://cyberelk.net/tim/patchutils/
  301. EOT
  302. }
  303. my $filename = bz_locations->{'localconfig'};
  304. if (scalar @old_vars) {
  305. my $oldstuff = join(', ', @old_vars);
  306. print <<EOT
  307. The following variables are no longer used in $filename, and
  308. should be removed: $oldstuff
  309. EOT
  310. }
  311. if (scalar @new_vars) {
  312. my $filename = bz_locations->{'localconfig'};
  313. my $fh = new IO::File($filename, '>>') || die "$filename: $!";
  314. $fh->seek(0, SEEK_END);
  315. foreach my $var (LOCALCONFIG_VARS) {
  316. if (grep($_ eq $var->{name}, @new_vars)) {
  317. print $fh "\n", $var->{desc},
  318. Data::Dumper->Dump([$localconfig->{$var->{name}}],
  319. ["*$var->{name}"]);
  320. }
  321. }
  322. # When updating site_wide_secret to the new value, don't
  323. # leave the old value behind.
  324. if (grep { $_ eq 'site_wide_secret' } @new_vars) {
  325. my $read = new IO::File($filename, '<') || die "$filename: $!";
  326. my $text;
  327. { local $/; $text = <$read> }
  328. $read->close;
  329. $text =~ s/^\$site_wide_secret = '\w{256}';$//ms;
  330. my $write = new IO::File($filename, '>') || die "$filename: $!";
  331. print $write $text;
  332. $write->close;
  333. }
  334. my $newstuff = join(', ', @new_vars);
  335. print <<EOT;
  336. This version of Bugzilla contains some variables that you may want to
  337. change and adapt to your local settings. Please edit the file
  338. $filename and rerun checksetup.pl.
  339. The following variables are new to $filename since you last ran
  340. checksetup.pl: $newstuff
  341. EOT
  342. exit;
  343. }
  344. # Reset the cache for Bugzilla->localconfig so that it will be re-read
  345. delete Bugzilla->request_cache->{localconfig};
  346. return { old_vars => \@old_vars, new_vars => \@new_vars };
  347. }
  348. sub _get_default_cvsbin { return bin_loc('cvs') }
  349. sub _get_default_interdiffbin { return bin_loc('interdiff') }
  350. sub _get_default_diffpath {
  351. my $diff_bin = bin_loc('diff');
  352. return dirname($diff_bin);
  353. }
  354. 1;
  355. __END__
  356. =head1 NAME
  357. Bugzilla::Install::Localconfig - Functions and variables dealing
  358. with the manipulation and creation of the F<localconfig> file.
  359. =head1 SYNOPSIS
  360. use Bugzilla::Install::Requirements qw(update_localconfig);
  361. update_localconfig({ output => 1 });
  362. =head1 DESCRIPTION
  363. This module is used primarily by L<checksetup.pl> to create and
  364. modify the localconfig file. Most scripts should use L<Bugzilla/localconfig>
  365. to access localconfig variables.
  366. =head1 CONSTANTS
  367. =over
  368. =item C<LOCALCONFIG_VARS>
  369. An array of hashrefs. These hashrefs contain three keys:
  370. name - The name of the variable.
  371. default - The default value for the variable. Should always be
  372. something that can fit in a scalar.
  373. desc - Additional text to put in localconfig before the variable
  374. definition. Must end in a newline. Each line should start
  375. with "#" unless you have some REALLY good reason not
  376. to do that.
  377. =item C<OLD_LOCALCONFIG_VARS>
  378. An array of names of variables. If C<update_localconfig> finds these
  379. variables defined in localconfig, it will print out a warning.
  380. =back
  381. =head1 SUBROUTINES
  382. =over
  383. =item C<read_localconfig($include_deprecated)>
  384. Description: Reads the localconfig file and returns all valid
  385. values in a hashref.
  386. Params: C<$include_deprecated> - C<true> if you want the returned
  387. hashref to also include variables listed in
  388. C<OLD_LOCALCONFIG_VARS>, if they exist. Generally
  389. this is only for use by C<update_localconfig>.
  390. Returns: A hashref of the localconfig variables. If an array
  391. is defined, it will be an arrayref in the returned hash. If a
  392. hash is defined, it will be a hashref in the returned hash.
  393. Only includes variables specified in C<LOCALCONFIG_VARS>
  394. (and C<OLD_LOCALCONFIG_VARS> if C<$include_deprecated> is
  395. specified).
  396. =item C<update_localconfig({ output =E<gt> 1 })>
  397. Description: Adds any new variables to localconfig that aren't
  398. currently defined there. Also optionally prints out
  399. a message about vars that *should* be there and aren't.
  400. Exits the program if it adds any new vars.
  401. Params: C<output> - C<true> if the function should display informational
  402. output and warnings. It will always display errors or
  403. any message which would cause program execution to halt.
  404. Returns: A hashref, with C<old_vals> being an array of names of variables
  405. that were removed, and C<new_vals> being an array of names
  406. of variables that were added to localconfig.
  407. =back