#!/usr/bin/perl -wT # # TWiki Enterprise Collaboration Platform, http://TWiki.org/ # # Copyright (C) 2000-2018 Peter Thoeny, peter[at]thoeny.org and # TWiki Contributors. All Rights Reserved. TWiki Contributors are # listed in the AUTHORS file in the root of this distribution. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 3 # of the License, or (at your option) any later version. For # more details read LICENSE in the root of this distribution. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # # As per the GPL, removal of this notice is prohibited. # # Configuration script for TWiki. Once you have a basic webserver # configuration that lets you access this script, the rest of the # configuration process is done from here. # # The script works from the top down, by checking features of the # environment before moving on. The sequence is: # 1. Check the version of perl # 2. Check we have the modules to run this script # 3. Check the environment # 4. Check we have the modules to load the rest of configure # ... and so on. At any stage, the script reports any errors in the # best way it can given the environment established so far. # When the basic checks are complete, the script moves into the # real configuration steps; setting configuration variables. # # This phase of the configure environment follows a Model-View- # Controller pattern. # # Controller # This script is the controller; it handles communication with the # browser (and thus the user). Communication is very simple; this script # is re-invoked with different 'action' parameters to determine what it does. # # Model # The Model consists of a simple node tree, where each node represents a # structural element in the *presentation* of the configuration (this may # not be consistent with the structure of $TWiki:cfg, so beware). Each # leaf node has an associated Type (in the Types subdirectory) that has # collected model and view behaviours for the basic types. # The Model is independent of the language used to represent the # configuration. There is one parser/generator provided, TWikiCfg, but it # would be trivial to add others. # # The View is a DOM document, generated as HTML by a set of UI classes. # Because of some convoluted history, there are actually three sets of classes # that generate views. They are all subclasses of TWiki::Configure::UI # UIs - are top-level and pluggable UI components. All the main screens are # implemented here. # Checkers - are specialised UIs designed to give checking support for # variable values. Checkers also include the read-only checking # UIs used for checking environment. # Types - provide some UI support in the form of type-specific prompters. # this is really an abuse of the Model, but it saves creating # decorator classes for all the Model types. # HTML is generated for the model using Visitor pattern. Each node in the tree # is visited in depth-first order. # use strict; use warnings; ########################################################### # VERY basic stuff required for configure to work. # Warnings are fatal $SIG{'__WARN__'} = sub { die @_ }; # We warn against running TWiki on an older Perl version then 5.8.4 # but we will not let configure die in this situation. The user # may have updated many libraries and tweaked TWiki so let us give # him a chance. my $perlversion = $]; if ( $perlversion < 5.010001 ) { print "Content-type: text/plain\n\n"; print <) || ''; }; eval { $WebServer_gid = join( ',', map { lc( getgrgid($_) ) } split( ' ', $( ) ); }; if ($@) { # Try to use Cygwin's 'id' command - may be on the path, since Cygwin # is probably installed to supply ls, egrep, etc - if it isn't, give # up. # Run command without stderr output, to avoid CGI giving error. # Get names of primary and other groups. $WebServer_gid = lc(qx(sh -c '( id -un ; id -gn) 2>/dev/null' 2>nul )); } my $localLibFailure; sub _loadBasicModule { my ($module) = @_; eval "use $module"; if ($@) { my $reason = "Failed to load the perl module $module. The module "; # See if we can find the .pm on @INC my $foundAt = "could not be found. "; my $modpath = $module; if ( $modpath =~ /^([\w:]+)/ ) { $modpath =~ s#::#/#g; $modpath .= '.pm'; foreach my $path (@INC) { if ( -e "$path/$modpath" ) { $foundAt = "was found at $path/$modpath"; if ( !-r "$path/$modpath" ) { $foundAt .= ", but I don't have permission to read it."; } last; } } } $reason .= $foundAt; $reason .= <splitdir($1); pop(@root); my @script = File::Spec->splitdir($0); my $scriptName = pop(@script); $scriptName =~ s/.*[\/\\]//; # Fix for Item3511, on Win XP # Try to load the LocalLib.cfg optional overload # Paths from LocalLib.cfg (preferred) use vars qw( $twikiLibPath @localPerlLibPath ); @INC = ('.', grep { $_ ne '.' } @INC); # setlib.cfg is in current directory eval 'require "setlib.cfg"'; if ($@) { # No joy. Remember the failure so we can report it later. $localLibFailure = $@; # Stick the root/lib on the path; there's a high probability we'll be # able to find the bits of TWiki::Configure that way. We will report # the setlib error later. unshift( @INC, File::Spec->catfile( @root, 'lib' ) ); } # Load all the bits of the configure module that we explicitly use # The loadBasicModule does some extra analysis on errors. foreach my $module ( 'CGI qw(:any)', 'CGI::Carp qw(fatalsToBrowser)', 'Cwd', 'Data::Dumper', 'File::Copy', 'File::Temp', 'TWiki::Configure::Checker', 'TWiki::Configure::CSS', 'TWiki::Configure::Item', 'TWiki::Configure::JS', 'TWiki::Configure::Load', 'TWiki::Configure::Pluggable', 'TWiki::Configure::Root', 'TWiki::Configure::Section', 'TWiki::Configure::Type', 'TWiki::Configure::Types::BOOLEAN', 'TWiki::Configure::Types::NUMBER', 'TWiki::Configure::Types::SELECT', 'TWiki::Configure::Types::STRING', 'TWiki::Configure::TWikiCfg', 'TWiki::Configure::UI', 'TWiki::Configure::UIs::Section', 'TWiki::Configure::Value', 'TWiki::Configure::Valuer', ) { _loadBasicModule($module); } $| = 1; # no buffering on STDOUT ########################################################### # From this point on we shouldn't have any more "fatal" (to configure) # errors, so we can report errors in the browser # We are configuring $TWiki::cfg, so we need to be in package TWiki from # now on. package TWiki; # We keep the actual config, and the default from TWiki.cfg, separate use vars qw( %cfg $defaultCfg ); # Declared in TWiki to support checkers use vars qw( $query ); # 'constants' used in TWiki.cfg use vars qw( $TRUE $FALSE ); $TRUE = 1; $FALSE = 0; # Remember what we detected previously, for use by Checkers if ( $scriptName =~ /(\.\w+)$/ ) { $TWiki::cfg{DETECTED}{ScriptExtension} = $1; } # very basic tool sub findFileOnPath { my $file = shift; $file =~ s(::)(/)g; foreach my $dir (@INC) { if ( -e "$dir/$file" ) { return "$dir/$file"; } } return undef; } ########################################################### # Grope the OS. This duplicates a bit of code in TWiki.pm, # but it has to be duplicated because we don't want to deal # with loading TWiki just yet. unless ( $TWiki::cfg{DetailedOS} ) { $TWiki::cfg{DetailedOS} = $^O; unless ( $TWiki::cfg{DetailedOS} ) { require Config; $TWiki::cfg{DetailedOS} = $Config::Config{osname}; } } unless ( $TWiki::cfg{OS} ) { if ( $TWiki::cfg{DetailedOS} =~ /darwin/i ) { # MacOS X $TWiki::cfg{OS} = 'UNIX'; } elsif ( $TWiki::cfg{DetailedOS} =~ /Win/i ) { $TWiki::cfg{OS} = 'WINDOWS'; } elsif ( $TWiki::cfg{DetailedOS} =~ /vms/i ) { $TWiki::cfg{OS} = 'VMS'; } elsif ( $TWiki::cfg{DetailedOS} =~ /bsdos/i ) { $TWiki::cfg{OS} = 'UNIX'; } elsif ( $TWiki::cfg{DetailedOS} =~ /dos/i ) { $TWiki::cfg{OS} = 'DOS'; } elsif ( $TWiki::cfg{DetailedOS} =~ /^MacOS$/i ) { # MacOS 9 or earlier $TWiki::cfg{OS} = 'MACINTOSH'; } elsif ( $TWiki::cfg{DetailedOS} =~ /os2/i ) { $TWiki::cfg{OS} = 'OS2'; } else { $TWiki::cfg{OS} = 'UNIX'; } } $query = new CGI; my $url = $query->url(); my $action = $query->param('action') || 'Configure'; my $expertsMode = defined( $query->param('expert') ); my $confirm = defined( $query->param('confirm') ) || 0; my $cfgAccess = $query->param('cfgAccess'); my $newCfgP = $query->param('newCfgP'); my $confCfgP = $query->param('confCfgP'); # Handle serving an image embedded in the configure page, before generating # any other output if ( $action eq 'image' ) { my $image = $query->param('image'); $image =~ /^([-.\w]+)$/; # filter-in $image = $1; if ( ( defined($image) ) && ( ( $image eq 'favicon.ico' ) || ( $image eq 'T-logo34x26-t.gif' ) || ( $image eq 'T-logo-140x40-t.gif' ) || ( $image eq 'warning.gif' ) || ( $image eq 'info.gif' ) ) ) { #ignore $query->param('type') and set it using our special knowledge my $type = 'image/gif'; if ( $image =~ /.*\.ico$/ ) { $type = 'image/x-icon'; } if ( open( my $F, '<', 'logos/' . $image ) ) { local $/ = undef; # SMELL: this call is correct, but causes a perl error # on some versions of CGI.pm # print $query->header(-type => $query->param('type')); # So use this instead: print 'Content-type: ' . $type . "\n\n"; print <$F>; close($F); } } exit 0; } my @meta = ( CGI::meta( { 'http-equiv' => 'Pragma', content => 'no-cache' } ), CGI::meta( { 'http-equiv' => 'Cache-Control', content => 'no-cache' } ), CGI::meta( { 'http-equiv' => 'Expires', content => 0 } ), CGI::meta( { name => 'robots', content => 'noindex' } ), CGI::Link( { -rel => 'icon', -href => $scriptName . '?action=image;image=favicon.ico;type=image/x-icon', -type => 'image/x-icon' } ), CGI::Link( { -rel => 'shortcut icon', -href => $scriptName . '?action=image;image=favicon.ico;type=image/x-icon', -type => 'image/x-icon' } ), CGI::script( { language => 'JavaScript', type => 'text/javascript' }, TWiki::Configure::JS::js1() ), CGI::style( { -type => 'text/css' }, TWiki::Configure::CSS::css() ), CGI::script( { language => 'JavaScript', type => 'text/javascript' }, TWiki::Configure::JS::js2() ), ); # Generate standard page header my $hdr = CGI::start_html( -title => 'TWiki Configuration', -head => \@meta, -class => 'patternNoViewPage' ); # XML header confuses IE, so strip it out. This is fixed in CGI.pm 3.06 # (and IE 7, but who's counting?) if ( $CGI::VERSION < 3.06 ) { $hdr =~ s/^<\?xml.*?>//s; } print CGI::header('text/html') . $hdr; print <<'HERE';
HERE # use this script recursively to serve the icon image print CGI::img( { src => $scriptName . '?action=image;image=T-logo-140x40-t.gif;type=image/gif', class => 'logo', alt => 'TWiki', width => '140', height => '40' } ); print "\n \n"; print CGI::h1( 'TWiki Configuration'); print "
\n"; my $stub = new TWiki::Configure::Item(); # This call will define $TWiki::defaultCfg by loading .spec files my $sanityUI = TWiki::Configure::UI::loadChecker( 'BasicSanity', $stub ); my ( $sanityStatement, $badLSC ) = $sanityUI->ui(); # This is the dispatcher; $action is the name of the action to perform, # this is concatenated to _action to determine the name of the procedure. # Dispatcher methods return a boolean to indicate whether to generate a # link back to the main page at the end. if ( $sanityUI->insane() || $query->param('abort') ) { print $sanityStatement; } else { if ( !defined $cfgAccess ) { my $newPass = $query->param('newCfgP'); if ( !defined($newPass) ) { $action = 'PromptPassword'; } else { $cfgAccess = $newPass; } } $action =~ s/\W//g; my $method = '_action' . $action; die "Undefined action $action" unless defined(&$method); no strict 'refs'; my $reroute = &$method(); use strict 'refs'; if ($reroute) { print '
'; print CGI::a( { href => $scriptName . '?t=' . time(), rel => 'nofollow' }, 'Return to configuration' ); print CGI::br(); print "
\n"; } } print <<'HERE';
 
HERE print CGI::end_html(), "\n"; ########################################################### # End of the main program; the rest is all subs sub _checkLoadUI { my ( $uiname, $root ) = @_; my $ui = TWiki::Configure::UI::loadUI( $uiname, $root ); unless ($ui) { print "Could not load $uiname UI. Error was:
$@
"; if ( $@ =~ /Can't locate (\S+)/ ) { print <loadCGIParams( $TWiki::query, \%updated ); # create the root of the UI my $root = new TWiki::Configure::Root(); my $ui; if ( !TWiki::Configure::UI::authorised() ) { $ui = _checkLoadUI( 'PromptPASS', $root ); return 1 unless $ui; print $ui->ui( 1, 'Configure' ); return 1; } #Here i am authenticated user #TODO - if authorisation fails - redirect to authentication form if ( !$confirm ) { print CGI::h2('Please Confirm the Following Changes'); print CGI::div( $modified . ' configuration item' . ( $modified == 1 ? ' was' : 's were' ) . ' changed' ); if ($modified) { print CGI::div( join( ' ', keys %updated ) ); } $ui = _checkLoadUI( 'AUTH', $root ); return 1 unless $ui; $ui->{newCfgP} = $ui->{newCfgP} = $newCfgP if defined $newCfgP; $ui->{confCfgP} = $confCfgP if defined $confCfgP; print $ui->ui( 1, 'Save' ); } else { # Load the specs from the .spec files and generate the UI template TWiki::Configure::TWikiCfg::load( $root, 1 ); $ui = _checkLoadUI( 'UPDATE', $root ); return 1 unless $ui; print $ui->ui( $root, $valuer, \%updated ); } return 1; } # Action invoked for prompting the Password on the main screen sub _actionPromptPassword { print CGI::h2( 'TWiki Administrator Login'); print $sanityStatement ; ## printing this in any case.. my $root = new TWiki::Configure::Root(); my $valuer = new TWiki::Configure::Valuer( $TWiki::defaultCfg, \%TWiki::cfg ); my %updated; my $modified = $valuer->loadCGIParams( $TWiki::query, \%updated ); print < HERE my $ui; if ( $badLSC ge 1 ) { # Load the specs from the .spec files and generate the UI template TWiki::Configure::TWikiCfg::load( $root, 1 ); my $newPass = $query->param('newCfgP'); if ($newPass) { if ( !TWiki::Configure::UI::authorised() ) { $ui = _checkLoadUI( 'SetNewPass', $root ); return 0 unless $ui; print $ui->ui( 1, 'Configure' ); } else { $ui = _checkLoadUI( 'AUTH', $root ); return 0 unless $ui; print $ui->ui( 1, 'Configure' ); } } else { $ui = _checkLoadUI( 'SetNewPass', $root ); return 0 unless $ui; print $ui->ui( 1, 'Configure' ); } return 0; } ## Password is verified and is correct... if ( !TWiki::Configure::UI::authorised() ) { ## TODO...Add meaningful line $ui = _checkLoadUI( 'PromptPASS', $root ); return 0 unless $ui; print $ui->ui( 1, 'Configure' ); } else { ## Password is verified and is correct... } return 0; } # Invoked by "find more extensions" button in the Extensions section sub _actionFindMoreExtensions { print CGI::h2('Find TWiki Extensions'); my $root = new TWiki::Configure::Root(); print '
'; my $ui = _checkLoadUI( 'EXTENSIONS', $root ); return 1 unless $ui; print $ui->ui(); return 1; } # Invoked when an extension is to be installed sub _actionInstallExtension { print CGI::h2('Install TWiki Extension'); my $root = new TWiki::Configure::Root(); my $ui; if ( !TWiki::Configure::UI::authorised() ) { $ui = _checkLoadUI( 'AUTH', $root ); return 1 unless $ui; print $ui->ui( 0, 'Install ' . ( $query->param('extension') || '' ) ); } else { $ui = _checkLoadUI( 'EXTEND', $root ); return 1 unless $ui; print $ui->ui(); } return 1; } # This is the default screen sub _actionConfigure { my $root = new TWiki::Configure::Root(); if ( !TWiki::Configure::UI::authorised() ) { my $ui = _checkLoadUI( 'PromptPASS', $root ); return 0 unless $ui; print $ui->ui( 1, 'Configure' ); return 0; } #Here i am authenticate $TWiki::Configure::UI::toterrors = 0; $TWiki::Configure::UI::totwarnings = 0; print CGI::h2('Modify Configuration Settings'); print $sanityStatement; # The first three sections go without a root my $stub = new TWiki::Configure::Item(); my $eui = TWiki::Configure::UI::loadChecker( 'Environment', $stub ); # See if this platform has special detection or checking requirements # (most don't) $stub = new TWiki::Configure::Item(); my $osui = TWiki::Configure::UI::loadChecker( $Config::Config{osname}, $stub ); $stub = new TWiki::Configure::Item(); my $cgiui = TWiki::Configure::UI::loadChecker( 'CGISetup', $stub ); # Use a separate root for the _saveable_ sections # my $root = new TWiki::Configure::Root(); my $valuer = new TWiki::Configure::Valuer( $TWiki::defaultCfg, \%TWiki::cfg ); # Load the config structures. TWiki::Configure::TWikiCfg::load( $root, !$badLSC ); if ( !$badLSC ) { print <

Use this page to set the configuration options for TWiki. Fill in the settings, and then press 'Next'.

Explanation of colors and symbols:
  • Settings marked like this are required (they must have a value).
  • Any errors in your configuration will be highlighted.
  • Warnings are non-fatal, but are often a good indicator that something that is wrong.
  • The little δ after an entry means that the current value is not the same as the default value. If you hover the cursor over the δ, a popup will show you what the default value is.
  • EXPERT means a setting is for expert use only. You should not fiddle with it unless you know what you are doing, or at least have read all the documentation. HERE if ( !$expertsMode ) { print <
HERE } print CGI::start_form( { name => 'update', action => $scriptName, method => "post" } ); # use time to make sure we never allow cacheing print CGI::hidden( 'time', time() ); print '
'; print CGI::div( { class => 'optionHeader' }, CGI::span( 'Settings' . CGI::span( { class => 'twikiSmall' }, 'Click the buttons below to open each section' ) ) . ' ' . CGI::span( { class => 'twikiSmall' }, CGI::a( { href => '#', rel => 'nofollow', onclick => 'toggleAllOptions(true); return false;' }, 'Open all options' ) ) ); print $eui->ui(); print $osui->ui() if $osui; print $cgiui->ui() if $cgiui; # Load the UI for the configuration and whack it out my $ui = _checkLoadUI( 'Root', $root ); return 1 unless $ui; $ui->{experts} = $expertsMode; print $ui->ui( $root, $valuer ); print "
\n"; if ( $TWiki::Configure::UI::toterrors || $TWiki::Configure::UI::totwarnings ) { my $mess = 'Total: ' . $TWiki::Configure::UI::toterrors . ' error' . ( $TWiki::Configure::UI::toterrors == 1 ? '' : 's' ) . ', ' . $TWiki::Configure::UI::totwarnings . ' warning' . ( $TWiki::Configure::UI::totwarnings == 1 ? '' : 's' ); print CGI::div($mess); } print CGI::hidden( 'cfgAccess', $cfgAccess ); print CGI::hidden( 'newCfgP', $newCfgP ) if defined $newCfgP; print CGI::hidden( 'confCfgP', $confCfgP ) if defined $confCfgP; print CGI::p( CGI::submit( -class => 'twikiSubmit', -name => 'action', -value => 'Next', -accesskey => 'N' ) ); print "Cancel and return to TWiki WebHome"; print CGI::end_form(); print <
DIVS return 0; } 1;