1 #============================================================= -*-perl-*-
3 # BackupPC::CGI::Lib package
7 # This library defines a BackupPC::Lib class and a variety of utility
8 # functions used by BackupPC.
11 # Craig Barratt <cbarratt@users.sourceforge.net>
14 # Copyright (C) 2003 Craig Barratt
16 # This program is free software; you can redistribute it and/or modify
17 # it under the terms of the GNU General Public License as published by
18 # the Free Software Foundation; either version 2 of the License, or
19 # (at your option) any later version.
21 # This program is distributed in the hope that it will be useful,
22 # but WITHOUT ANY WARRANTY; without even the implied warranty of
23 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 # GNU General Public License for more details.
26 # You should have received a copy of the GNU General Public License
27 # along with this program; if not, write to the Free Software
28 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 #========================================================================
32 # Version 2.1.0_CVS, released 3 Jul 2003.
34 # See http://backuppc.sourceforge.net.
36 #========================================================================
38 package BackupPC::CGI::Lib;
45 use vars qw( @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS );
47 use vars qw($Cgi %In $MyURL $User %Conf $TopDir $BinDir $bpc);
48 use vars qw(%Status %Info %Jobs @BgQueue @UserQueue @CmdQueue
49 %QueueLen %StatusHost);
50 use vars qw($Hosts $HostsMTime $ConfigMTime $PrivAdmin);
51 use vars qw(%UserEmailInfo $UserEmailInfoMTime %RestoreReq);
79 $Cgi %In $MyURL $User %Conf $TopDir $BinDir $bpc
80 %Status %Info %Jobs @BgQueue @UserQueue @CmdQueue
82 $Hosts $HostsMTime $ConfigMTime $PrivAdmin
83 %UserEmailInfo $UserEmailInfoMTime %RestoreReq
88 'all' => [ @EXPORT_OK ],
97 # We require that Apache pass in $ENV{SCRIPT_NAME} and $ENV{REMOTE_USER}.
98 # The latter requires .ht_access style authentication. Replace this
99 # code if you are using some other type of authentication, and have
100 # a different way of getting the user name.
102 $MyURL = $ENV{SCRIPT_NAME};
103 $User = $ENV{REMOTE_USER};
105 if ( !defined($bpc) ) {
106 ErrorExit($Lang->{BackupPC__Lib__new_failed__check_apache_error_log})
107 if ( !($bpc = BackupPC::Lib->new(undef, undef, 1)) );
108 $TopDir = $bpc->TopDir();
109 $BinDir = $bpc->BinDir();
110 %Conf = $bpc->Conf();
111 $Lang = $bpc->Lang();
112 $ConfigMTime = $bpc->ConfigMTime();
113 } elsif ( $bpc->ConfigMTime() != $ConfigMTime ) {
115 %Conf = $bpc->Conf();
116 $ConfigMTime = $bpc->ConfigMTime();
117 $Lang = $bpc->Lang();
121 # Clean up %ENV for taint checking
123 delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
124 $ENV{PATH} = $Conf{MyPath};
127 # Verify we are running as the correct user
129 if ( $Conf{BackupPCUserVerify}
130 && $> != (my $uid = (getpwnam($Conf{BackupPCUser}))[2]) ) {
131 ErrorExit(eval("qq{$Lang->{Wrong_user__my_userid_is___}}"), <<EOF);
132 This script needs to run as the user specified in \$Conf{BackupPCUser},
133 which is set to $Conf{BackupPCUser}.
135 This is an installation problem. If you are using mod_perl then
136 it appears that Apache is not running as user $Conf{BackupPCUser}.
137 If you are not using mod_perl, then most like setuid is not working
138 properly on BackupPC_Admin. Check the permissions on
139 $Conf{CgiDir}/BackupPC_Admin and look at the documentation.
143 if ( !defined($Hosts) || $bpc->HostsMTime() != $HostsMTime ) {
144 $HostsMTime = $bpc->HostsMTime();
145 $Hosts = $bpc->HostInfoRead();
147 # turn moreUsers list into a hash for quick lookups
148 foreach my $host (keys %$Hosts) {
149 $Hosts->{$host}{moreUsers} =
150 {map {$_, 1} split(",", $Hosts->{$host}{moreUsers}) }
157 my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)
158 = localtime($_[0] == 0 ? time : $_[0] );
161 if ( $Conf{CgiDateFormatMMDD} ) {
162 return sprintf("$mon/$mday %02d:%02d", $hour, $min);
164 return sprintf("$mday/$mon %02d:%02d", $hour, $min);
172 if ( defined($Hosts->{$host}) || defined($Status{$host}) ) {
173 $s = "<a href=\"$MyURL?host=${EscURI($host)}\">$host</a>";
185 return \$user if ( $user eq ""
186 || $Conf{CgiUserUrlCreate} eq "" );
187 if ( $Conf{CgiUserHomePageCheck} eq ""
188 || -f sprintf($Conf{CgiUserHomePageCheck}, $user, $user, $user) ) {
190 . sprintf($Conf{CgiUserUrlCreate}, $user, $user, $user)
205 $s =~ s{([^[:print:]])}{sprintf("&\#x%02X;", ord($1));}eg;
212 $s =~ s{([^\w.\/-])}{sprintf("%%%02X", ord($1));}eg;
219 my($head) = shift(@mesg);
220 my($mesg) = join("</p>\n<p>", @mesg);
221 $Conf{CgiHeaderFontType} ||= "arial";
222 $Conf{CgiHeaderFontSize} ||= "3";
223 $Conf{CgiNavBarBgColor} ||= "#ddeeee";
224 $Conf{CgiHeaderBgColor} ||= "#99cc33";
226 if ( !defined($ENV{REMOTE_USER}) ) {
229 Note: \$ENV{REMOTE_USER} is not set, which could mean there is an
230 installation problem. BackupPC_Admin expects Apache to authenticate
231 the user and pass their user name into this script as the REMOTE_USER
232 environment variable. See the documentation.
236 $bpc->ServerMesg("log User $User (host=$In{host}) got CGI error: $head")
237 if ( defined($bpc) );
238 if ( !defined($Lang->{Error}) ) {
239 Header("BackupPC: Error");
240 $mesg = <<EOF if ( !defined($mesg) );
241 There is some problem with the BackupPC installation.
242 Please check the permissions on BackupPC_Admin.
245 ${h1("Error: Unable to read config.pl or language strings!!")}
250 Header(eval("qq{$Lang->{Error}}"));
251 print (eval("qq{$Lang->{Error____head}}"));
260 # Verify that the server connection is ok
262 return if ( $bpc->ServerOK() );
263 $bpc->ServerDisconnect();
264 if ( my $err = $bpc->ServerConnect($Conf{ServerHost}, $Conf{ServerPort}) ) {
265 ErrorExit(eval("qq{$Lang->{Unable_to_connect_to_BackupPC_server}}"));
273 my $reply = $bpc->ServerMesg("status $status");
274 $reply = $1 if ( $reply =~ /(.*)/s );
276 # ignore status related to admin and trashClean jobs
277 if ( $status =~ /\bhosts\b/ ) {
278 delete($Status{$bpc->adminJob});
279 delete($Status{$bpc->trashJob});
283 sub ReadUserEmailInfo
285 if ( (stat("$TopDir/log/UserEmailInfo.pl"))[9] != $UserEmailInfoMTime ) {
286 do "$TopDir/log/UserEmailInfo.pl";
287 $UserEmailInfoMTime = (stat("$TopDir/log/UserEmailInfo.pl"))[9];
292 # Check if the user is privileged. A privileged user can access
293 # any information (backup files, logs, status pages etc).
295 # A user is privileged if they belong to the group
296 # $Conf{CgiAdminUserGroup}, or they are in $Conf{CgiAdminUsers}
297 # or they are the user assigned to a host in the host file.
304 return 0 if ( $User eq "" && $Conf{CgiAdminUsers} ne "*"
305 || $host ne "" && !defined($Hosts->{$host}) );
306 if ( $Conf{CgiAdminUserGroup} ne "" ) {
307 my($n,$p,$gid,$mem) = getgrnam($Conf{CgiAdminUserGroup});
308 $Privileged ||= ($mem =~ /\b$User\b/);
310 if ( $Conf{CgiAdminUsers} ne "" ) {
311 $Privileged ||= ($Conf{CgiAdminUsers} =~ /\b$User\b/);
312 $Privileged ||= $Conf{CgiAdminUsers} eq "*";
314 $PrivAdmin = $Privileged;
315 $Privileged ||= $User eq $Hosts->{$host}{user};
316 $Privileged ||= defined($Hosts->{$host}{moreUsers}{$User});
322 # Returns the list of hosts that should appear in the navigation bar
323 # for this user. If $Conf{CgiNavBarAdminAllHosts} is set, the admin
324 # gets all the hosts. Otherwise, regular users get hosts for which
325 # they are the user or are listed in the moreUsers column in the
330 if ( $Conf{CgiNavBarAdminAllHosts} && CheckPermission() ) {
331 return sort keys %$Hosts;
334 return sort grep { $Hosts->{$_}{user} eq $User ||
335 defined($Hosts->{$_}{moreUsers}{$User}) } keys(%$Hosts);
339 # Given a host name tries to find the IP address. For non-dhcp hosts
340 # we just return the host name. For dhcp hosts we check the address
341 # the user is using ($ENV{REMOTE_ADDR}) and also the last-known IP
342 # address for $host. (Later we should replace this with a broadcast
350 if ( defined($Hosts->{$host}) && $Hosts->{$host}{dhcp}
351 && $ENV{REMOTE_ADDR} =~ /^(\d+[\.\d]*)$/ ) {
353 my($netBiosHost, $netBiosUser) = $bpc->NetBiosInfoGet($ipAddr);
354 if ( $netBiosHost ne $host ) {
356 GetStatusInfo("host(${EscURI($host)})");
357 if ( defined($StatusHost{dhcpHostIP})
358 && $StatusHost{dhcpHostIP} ne $ipAddr ) {
359 $tryIP = eval("qq{$Lang->{tryIP}}");
360 ($netBiosHost, $netBiosUser)
361 = $bpc->NetBiosInfoGet($StatusHost{dhcpHostIP});
363 if ( $netBiosHost ne $host ) {
364 ErrorExit(eval("qq{$Lang->{Can_t_find_IP_address_for}}"),
365 eval("qq{$Lang->{host_is_a_DHCP_host}}"));
367 $ipAddr = $StatusHost{dhcpHostIP};
373 ###########################################################################
374 # HTML layout subroutines
375 ###########################################################################
381 { link => "", name => $Lang->{Status},
383 { link => "?action=summary", name => $Lang->{PC_Summary} },
384 { link => "?action=view&type=LOG", name => $Lang->{LOG_file} },
385 { link => "?action=LOGlist", name => $Lang->{Old_LOGs} },
386 { link => "?action=emailSummary", name => $Lang->{Email_summary} },
387 { link => "?action=view&type=config", name => $Lang->{Config_file} },
388 { link => "?action=view&type=hosts", name => $Lang->{Hosts_file} },
389 { link => "?action=queue", name => $Lang->{Current_queues} },
390 { link => "?action=view&type=docs", name => $Lang->{Documentation},
392 { link => "http://backuppc.sourceforge.net/faq", name => "FAQ",
394 { link => "http://backuppc.sourceforge.net", name => "SourceForge",
397 print $Cgi->header();
399 <!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN">
401 <title>$title</title>
403 </head><body bgcolor="$Conf{CgiBodyBgColor}">
404 <table cellpadding="0" cellspacing="0" border="0">
405 <tr valign="top"><td valign="top" bgcolor="$Conf{CgiNavBarBgColor}" width="10%">
407 NavSectionTitle("BackupPC");
409 if ( defined($In{host}) && defined($Hosts->{$In{host}}) ) {
410 my $host = $In{host};
411 NavSectionTitle( eval("qq{$Lang->{Host_Inhost}}") );
413 NavLink("?host=${EscURI($host)}", $Lang->{Home});
414 NavLink("?action=view&type=LOG&host=${EscURI($host)}", $Lang->{LOG_file});
415 NavLink("?action=LOGlist&host=${EscURI($host)}", $Lang->{Old_LOGs});
416 if ( -f "$TopDir/pc/$host/SmbLOG.bad"
417 || -f "$TopDir/pc/$host/SmbLOG.bad.z"
418 || -f "$TopDir/pc/$host/XferLOG.bad"
419 || -f "$TopDir/pc/$host/XferLOG.bad.z" ) {
420 NavLink("?action=view&type=XferLOGbad&host=${EscURI($host)}",
421 $Lang->{Last_bad_XferLOG});
422 NavLink("?action=view&type=XferErrbad&host=${EscURI($host)}",
423 $Lang->{Last_bad_XferLOG_errors_only});
425 if ( -f "$TopDir/pc/$host/config.pl" ) {
426 NavLink("?action=view&type=config&host=${EscURI($host)}", $Lang->{Config_file});
430 NavSectionTitle($Lang->{NavSectionTitle_});
432 foreach my $l ( @adminLinks ) {
433 if ( $PrivAdmin || $l->{priv} ) {
434 NavLink($l->{link}, $l->{name});
436 NavLink(undef, $l->{name});
440 NavSectionTitle($Lang->{Hosts});
442 <table cellpadding="2" cellspacing="0" border="0" width="100%">
443 <tr><td>$Lang->{Host_or_User_name}</td>
444 <tr><td><form action="$MyURL" method="get"><small>
445 <input type="text" name="host" size="10" maxlength="64">
446 <input type="hidden" name="action" value="hostInfo"><input type="submit" value="$Lang->{Go}" name="ignore">
447 </small></form></td></tr>
450 if ( defined($Hosts) && %$Hosts > 0 ) {
452 foreach my $host ( GetUserHosts() ) {
453 NavLink("?host=${EscURI($host)}", $host);
458 </td><td valign="top" width="5"> </td>
459 <td valign="top" width="90%">
476 <table cellpadding="2" cellspacing="0" border="0" width="100%">
477 <tr><td bgcolor="$Conf{CgiHeaderBgColor}"><font face="$Conf{CgiHeaderFontType}"
478 size="$Conf{CgiHeaderFontSize}"><b>$head</b>
488 $padding = 1 if ( !defined($padding) );
490 <table cellpadding="$padding" cellspacing="0" border="0" width="100%">
501 my($link, $text) = @_;
502 print "<tr><td width=\"2%\" valign=\"top\"><b>·</b></td>";
503 if ( defined($link) ) {
504 $link = "$MyURL$link" if ( $link eq "" || $link =~ /^\?/ );
506 <td width="98%"><a href="$link"><small>$text</small></a></td></tr>
510 <td width="98%"><small>$text</small></td></tr>
519 <table cellpadding="2" cellspacing="0" border="0" width="100%">
521 <td bgcolor="$Conf{CgiHeaderBgColor}"> <font face="$Conf{CgiHeaderFontType}"
522 size="$Conf{CgiHeaderFontSize}"><b>$str</b></font>
532 <table cellpadding="2" cellspacing="0" border="0" width="100%">
534 <td bgcolor="$Conf{CgiHeaderBgColor}"> <font face="$Conf{CgiHeaderFontType}"
535 size="$Conf{CgiHeaderFontSize}"><b>$str</b></font>