Changeset 1257

Show
Ignore:
Timestamp:
18/11/06 23:47:02 (5 years ago)
Author:
janl
Message:

Run tidyperl on munin-node and munin-run, some very basic cleanup and module use.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • people/janl/src/libperl/Munin.pm

    r1256 r1257  
    345345} ## end sub munin_get 
    346346 
     347 
     348sub copyright { 
     349    # Return a string containing copyright and licensing information. 
     350    return <<"EOM" 
     351Written by Audun Ytterdal, Jimmy Olsen, Tore Anderson, Nicolai Langfeldt  
     352 
     353Copyright (C) 2002-2006 by the authors. 
     354 
     355The work has in part been financed by Linpro AS. http://linpro.no/ 
     356 
     357This is free software released under the GNU General Public License. There 
     358is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     359PURPOSE. For details, please refer to the file COPYING that is included 
     360with this software or refer to 
     361  http://www.fsf.org/licensing/licenses/gpl.txt 
     362EOM 
     363} 
     364 
    347365# Return true to mark successful inclusion of module. 
    3483661; 
  • people/janl/src/libperl/Munin/Node.pm

    r1248 r1257  
    1 package Muninnode; 
    2 # Copyright (C) 2004-2006 Audun Ytterdal, Jimmy Olsen, Nicolai Langfeldt 
     1package Munin::Node; 
     2# Copyright (C) 2006 Nicolai Langfeldt 
    33# 
    44# This program is free software; you can redistribute it and/or 
     
    1919 
    2020use Exporter; 
    21 @ISA = ('Exporter'); 
    22 @EXPORT=(); 
     21@ISA = qw(main Exporter); 
     22@EXPORT=qw(clean_envir); 
    2323 
    2424use strict; 
    2525 
    26 my $VERSION = '@@VERSION@@'; 
    27 my $CONFDIR = '@@CONFDIR@@'; 
    28 my $PLUGINUSER = '@@PLUGINUSER@@'; 
    29 my $GROUP = '@@GROUP@@'; 
    30 my $STATEDIR = '@@STATEDIR@@'; 
    31 my $PLUGSTATE = '@@PLUGSTATE@@'; 
     26sub clean_envir { 
     27    # "Clean" environment to disable taint-checking on the environment. We 
     28    # _know_ that the environment is insecure, but we want to let admins 
     29    # shoot themselves in the foot with it, if they want to. 
     30     
     31    foreach my $key ( keys %ENV ) { 
     32        # Remove all locale settings so that we get "." as decimal point 
     33        # and so on. 
     34        if (substr( $key, 0, 3 ) eq 'LC_' or 
     35            substr( $key, 0, 4 ) eq 'LANG' ) { 
     36            delete( $ENV{$key} ); 
     37            next; 
     38        } 
     39     
     40        $ENV{$key} =~ /^(.*)$/; 
     41        $ENV{$key} = $1; 
     42    } 
     43
  • people/janl/src/node/munin-node

    r1249 r1257  
    1 #!@@PERL@@ -wT 
    2 # -*- cperl -*- 
     1#!/usr/bin/perl -wT 
    32# 
    43# Copyright (C) 2002-2006 Audun Ytterdal, Jimmy Olsen, Tore Anderson, 
     
    2827use Getopt::Long; 
    2928use Munin; 
    30 use Net::Server::Fork; # any personality will do 
     29use Munin::Node; 
     30use Net::Server::Fork; 
    3131 
    3232my $tls; 
    33 my %tls_verified = ( "level" => 0, "cert" => "", "verified" => 0, "required_depth" => 5 ); 
    34  
    35 chdir ("/"); 
    36  
    37 # "Clean" environment to disable taint-checking on the environment. We _know_ 
    38 # that the environment is insecure, but we want to let admins shoot themselves 
    39 # in the foot with it, if they want to. 
    40 foreach my $key (keys %ENV) 
    41 
    42         $ENV{$key} =~ /^(.*)$/; 
    43         $ENV{$key} = $1; 
    44 
    45  
    46 $0 =~ /^(.*)$/; # for some strange reason won't "$0 = $0;" work. 
     33my %tls_verified = ( 
     34    "level"          => 0, 
     35    "cert"           => "", 
     36    "verified"       => 0, 
     37    "required_depth" => 5 
     38); 
     39 
     40chdir("/"); 
     41 
     42clean_envir; 
     43 
     44$0 =~ /^(.*)$/;    # for some strange reason won't "$0 = $0;" work. 
    4745$0 = $1; 
    4846 
     
    5149my %services; 
    5250my %nodes; 
    53 my $servicedir="@@CONFDIR@@/plugins"; 
    54 my $sconfdir="@@CONFDIR@@/plugin-conf.d"; 
    55 my $conffile="@@CONFDIR@@/munin-node.conf"; 
    56 my $FQDN=""; 
    57 my $do_usage = 0; 
    58 my $DEBUG = 0; 
     51my $servicedir = "$CONFDIR/plugins"; 
     52my $sconfdir   = "$CONFDIR/plugin-conf.d"; 
     53my $conffile   = "$CONFDIR/munin-node.conf"; 
     54my $FQDN       = ""; 
     55my $do_usage   = 0; 
     56my $DEBUG      = 0; 
    5957my $do_version = 0; 
    60 my $VERSION=$Muninnode::VERSION; 
    61 my $defuser = getpwnam ("@@PLUGINUSER@@"); 
    62 my $defgroup= getgrnam ("@@GROUP@@"); 
    63 my $paranoia= 0; 
    64 my @ignores = (); 
    65 my %sconf   = ('timeout' => 10); 
    66 my $caddr   = ""; 
    67  
    68 $do_usage=1  unless  
    69 GetOptions ( "config=s"     => \$conffile, 
    70              "debug!"       => \$DEBUG, 
    71              "version!"     => \$do_version, 
    72              "paranoia!"    => \$paranoia, 
    73              "help"         => \$do_usage ); 
    74  
    75 if ($do_usage) 
    76 
     58my $VERSION    = '@@VERSION@@'; 
     59my $defuser    = getpwnam($PLUGINUSER); 
     60my $defgroup   = getgrnam($GROUP); 
     61my $paranoia   = 0; 
     62my @ignores    = (); 
     63my %sconf      = ( 'timeout' => 10 ); 
     64my $caddr      = ""; 
     65 
     66$do_usage = 1 
     67  unless GetOptions( 
     68    "config=s"  => \$conffile, 
     69    "debug!"    => \$DEBUG, 
     70    "version!"  => \$do_version, 
     71    "paranoia!" => \$paranoia, 
     72    "help"      => \$do_usage 
     73  ); 
     74 
     75if ($do_usage) { 
    7776    print "Usage: $0 [options] 
    7877 
     
    9089} 
    9190 
    92 if ($do_version) 
    93 
    94         print "munin-node (munin-node) version $VERSION. 
    95 Written by Audun Ytterdal, Jimmy Olsen, Tore Anderson / Linpro AS 
    96  
    97 Copyright (C) 2002-2005 
    98  
    99 This is free software released under the GNU General Public License. There 
    100 is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR 
    101 PURPOSE. For details, please refer to the file COPYING that is included 
    102 with this software or refer to 
    103   http://www.fsf.org/licensing/licenses/gpl.txt 
    104 "; 
    105         exit 0; 
     91if ($do_version) { 
     92    print "munin-node (munin-node) version $VERSION.". 
     93    Munin::copyright; 
     94    exit 0; 
    10695} 
    10796 
     
    111100# Check permissions of configuration 
    112101 
    113 if (!&check_perms ($servicedir) or !&check_perms ($conffile)) 
    114 
    115         die "Fatal error. Bailing out."; 
    116 
    117  
    118 if (! -f $conffile) { 
    119   print "ERROR: Cannot open $conffile\n"; 
    120   exit 1; 
     102if ( !&check_perms($servicedir) or !&check_perms($conffile) ) { 
     103    die "Fatal error. Bailing out."; 
     104
     105 
     106if ( !-f $conffile ) { 
     107    print "ERROR: Cannot open $conffile\n"; 
     108    exit 1; 
    121109} 
    122110 
    123111# A hack to overide the hostname if everyhing thing else fails 
    124 open FILE,$conffile or die "Cannot open $conffile\n"; 
     112open FILE, $conffile or die "Cannot open $conffile\n"; 
    125113while (<FILE>) { 
    126   chomp; 
    127   s/#.*//;                # no comments 
    128   s/^\s+//;               # no leading white 
    129   s/\s+$//;               # no trailing white 
    130   next unless length;     # anything left? 
    131   /(^\w*)\s+(.*)/; 
    132   if (($1 eq "host_name" or $1 eq "hostname") and $2) 
    133   { 
    134       $FQDN=$2; 
    135   } 
    136   elsif (($1 eq "default_plugin_user" or $1 eq "default_client_user") and $2) 
    137   { 
    138       my $tmpid = $2; 
    139       $defuser = &get_uid ($tmpid); 
    140       if (! defined ($defuser)) 
    141       { 
    142           die "Default user defined in \"$conffile\" does not exist ($tmpid)"; 
    143       } 
    144   } 
    145   elsif (($1 eq "default_plugin_group" or $1 eq "default_client_group") and $2) 
    146   { 
    147       my $tmpid = $2; 
    148       $defgroup = &get_gid ($tmpid); 
    149       if (! defined ($defgroup)) 
    150       { 
    151           die "Default group defined in \"$conffile\" does not exist ($tmpid)"; 
    152       } 
    153   } 
    154   elsif (($1 eq "paranoia") and defined $2) 
    155   { 
    156           if ("$2" eq "no" or "$2" eq "false" or "$2" eq "off" or "$2" eq "0") 
    157           { 
    158                   $paranoia = 0; 
    159           } 
    160           else 
    161           { 
    162                   $paranoia = 1; 
    163           } 
    164   } 
    165   elsif (($1 eq "ignore_file") and defined $2) 
    166   { 
    167       push @ignores, $2; 
    168   } 
    169   elsif (($1 eq "timeout") and defined $2) 
    170   { 
    171       $sconf{'timeout'} = $2; 
    172   } 
    173   elsif (defined $1 and defined $2 and not defined $sconf{$1}) 
    174   { 
    175       $sconf{$1} = $2; 
    176   } 
    177 
     114    chomp; 
     115    s/#.*//;     # no comments 
     116    s/^\s+//;    # no leading white 
     117    s/\s+$//;    # no trailing white 
     118    next unless length;    # anything left? 
     119    /(^\w*)\s+(.*)/; 
     120    if ( ( $1 eq "host_name" or $1 eq "hostname" ) and $2 ) { 
     121        $FQDN = $2; 
     122    } elsif ( ( $1 eq "default_plugin_user" or $1 eq "default_client_user" ) 
     123        and $2 ) 
     124    { 
     125        my $tmpid = $2; 
     126        $defuser = &get_uid($tmpid); 
     127        if ( !defined($defuser) ) { 
     128            die 
     129              "Default user defined in '$conffile' does not exist ($tmpid)"; 
     130        } 
     131    } elsif ( ( $1 eq "default_plugin_group" or $1 eq "default_client_group" ) 
     132        and $2 ) { 
     133        my $tmpid = $2; 
     134        $defgroup = &get_gid($tmpid); 
     135        if ( !defined($defgroup) ) { 
     136            die "Default group defined in '$conffile' does not exist ($tmpid)"; 
     137        } 
     138    } elsif ( ( $1 eq "paranoia" ) and defined $2 ) { 
     139        if ( "$2" eq "no" or "$2" eq "false" or "$2" eq "off" or "$2" eq "0" ) 
     140        { 
     141            $paranoia = 0; 
     142        } else { 
     143            $paranoia = 1; 
     144        } 
     145    } elsif ( ( $1 eq "ignore_file" ) and defined $2 ) { 
     146        push @ignores, $2; 
     147    } elsif ( ( $1 eq "timeout" ) and defined $2 ) { 
     148        $sconf{'timeout'} = $2; 
     149    } elsif ( defined $1 and defined $2 and not defined $sconf{$1} ) { 
     150        $sconf{$1} = $2; 
     151    } 
     152} ## end while (<FILE>) 
    178153 
    179154$FQDN ||= &get_fq_hostname; 
    180155 
    181 $ENV{FQDN}=$FQDN; 
    182  
    183 # Some locales uses "," as decimal separator. This can mess up a lot 
    184 # of plugins. 
    185 $ENV{'LC_ALL'}='C'; 
    186  
    187 MyPackage->run(conf_file => $conffile, 
    188                pid_file => "@@STATEDIR@@/munin-node.pid"); 
    189 exit; 
    190  
    191  
    192  
     156$ENV{FQDN} = $FQDN; 
     157 
     158MyPackage->run( 
     159    conf_file => $conffile, 
     160    pid_file  => "@@STATEDIR@@/munin-node.pid" 
     161); 
     162exit;     
    193163 
    194164### over-ridden subs below 
     
    196166sub pre_loop_hook { 
    197167    my $self = shift; 
    198        print STDERR "In pre_loop_hook.\n" if $DEBUG; 
     168    print STDERR "In pre_loop_hook.\n" if $DEBUG; 
    199169    &load_services; 
    200170    $self->SUPER::pre_loop_hook; 
     
    202172 
    203173sub show_version { 
    204   print "munins node on $FQDN version: $VERSION\n" 
     174    print "munins node on $FQDN version: $VERSION\n"; 
     175    print "Munin.pm version $Munin::VERSION\n"; 
     176    print "Munin::Node.pm version $Munin::Node::VERSION\n"; 
    205177} 
    206178 
    207179sub show_nodes { 
    208   for my $node (keys %nodes) { 
    209     net_write ("$node\n"); 
    210  
    211   net_write (".\n"); 
     180    for my $node ( keys %nodes ) { 
     181        net_write("$node\n"); 
     182   
     183    net_write(".\n"); 
    212184} 
    213185 
     
    216188    eval { 
    217189        require Sys::Hostname; 
    218         $hostname = (gethostbyname(Sys::Hostname::hostname()))[0]; 
     190        $hostname = ( gethostbyname( Sys::Hostname::hostname() ) )[0]; 
    219191    }; 
    220192    return $hostname if $hostname; 
    221193 
    222     $hostname = `hostname`;  # Fall$ 
     194    $hostname = `hostname`;    # Fall$ 
    223195    chomp($hostname); 
    224196    $hostname =~ s/\s//g; 
     
    227199 
    228200sub load_services { 
    229     if (opendir (DIR,$sconfdir)) 
    230     { 
    231 FILES: 
    232         for my $file (grep { -f "$sconfdir/$_" } readdir (DIR)) 
    233         { 
    234             next if $file =~ m/^\./; # Hidden files 
    235             next if $file !~ m/^([-\w.]+)$/; # Skip if any weird chars 
    236             $file = $1; # Not tainted anymore. 
    237             foreach my $regex (@ignores) 
    238             { 
    239                 next FILES if $file =~ /$regex/; 
    240             } 
    241             if (!&load_auth_file ($sconfdir, $file, \%sconf)) 
    242             { 
    243                 warn "Something wicked happened while reading \"$servicedir/$file\". Check the previous log lines for spesifics."; 
    244             } 
    245         } 
    246         closedir (DIR); 
    247     } 
    248  
    249     opendir (DIR,$servicedir) || die "Cannot open plugindir: $servicedir $!"; 
    250 FILES: 
    251     for my $file (grep { -f "$servicedir/$_" } readdir(DIR)) { 
    252         next if $file =~ m/^\./; # Hidden files 
    253         next if $file =~ m/.conf$/; # Config files 
    254         next if $file !~ m/^([-\w.]+)$/; # Skip if any weird chars 
    255         $file = $1; # Not tainted anymore. 
    256         foreach my $regex (@ignores) 
    257         { 
    258             next FILES if $file =~ /$regex/; 
    259         } 
    260         next if (! -x "$servicedir/$file"); # File not executeable 
    261         print "file: '$file'\n" if $DEBUG; 
    262         $services{$file}=1; 
    263         my @rows = &run_service($file,"config", 1); 
    264         my $node = &get_var (\%sconf, $file, 'host_name'); 
    265  
    266         for my $row (@rows) { 
    267           print "row: $row\n" if $DEBUG; 
    268           if ($row =~ m/^host_name (.+)$/) { 
    269             print "Found host_name, using it\n" if $DEBUG; 
    270             $node = $1; 
    271           } 
    272         }  
    273         $node ||= $FQDN; 
    274         $nodes{$node}{$file}=1; 
    275     } 
     201    if ( opendir( DIR, $sconfdir ) ) { 
     202      FILES: 
     203        for my $file ( grep { -f "$sconfdir/$_" } readdir(DIR) ) { 
     204            next if $file =~ m/^\./;    # Hidden files 
     205            next if $file !~ m/^([-\w.]+)$/;    # Skip if any weird chars 
     206            $file = $1;                         # Not tainted anymore. 
     207            foreach my $regex (@ignores) { 
     208                next FILES if $file =~ /$regex/; 
     209            } 
     210            if ( !&load_auth_file( $sconfdir, $file, \%sconf ) ) { 
     211                warn "Something wicked happened while reading ". 
     212                    "'$servicedir/$file'. Check the previous log ". 
     213                    "lines for spesifics."; 
     214            } 
     215        } 
     216        closedir(DIR); 
     217    } ## end if ( opendir( DIR, $sconfdir... 
     218 
     219    opendir( DIR, $servicedir ) 
     220      || die "Cannot open plugindir: $servicedir $!"; 
     221  FILES: 
     222    for my $file ( grep { -f "$servicedir/$_" } readdir(DIR) ) { 
     223        next if $file =~ m/^\./;       # Hidden files 
     224        next if $file =~ m/.conf$/;    # Config files 
     225        next if $file !~ m/^([-\w.]+)$/;    # Skip if any weird chars 
     226        $file = $1;                         # Not tainted anymore. 
     227        foreach my $regex (@ignores) { 
     228            next FILES if $file =~ /$regex/; 
     229        } 
     230        next if ( !-x "$servicedir/$file" );    # File not executeable 
     231        print "file: '$file'\n" if $DEBUG; 
     232        $services{$file} = 1; 
     233        my @rows = &run_service( $file, "config", 1 ); 
     234        my $node = &get_var( \%sconf, $file, 'host_name' ); 
     235 
     236        for my $row (@rows) { 
     237            print "row: $row\n" if $DEBUG; 
     238            if ( $row =~ m/^host_name (.+)$/ ) { 
     239                print "Found host_name, using it\n" if $DEBUG; 
     240                $node = $1; 
     241            } 
     242        } 
     243        $node ||= $FQDN; 
     244        $nodes{$node}{$file} = 1; 
     245    } ## end for my $file ( grep { -f... 
    276246    closedir DIR; 
    277 } 
     247} ## end sub load_services 
    278248 
    279249sub print_service { 
    280   my (@lines) = @_; 
    281   for my $line (@lines) { 
    282     net_write ("$line\n"); 
    283  
    284   net_write (".\n"); 
     250    my (@lines) = @_; 
     251    for my $line (@lines) { 
     252        net_write("$line\n"); 
     253   
     254    net_write(".\n"); 
    285255} 
    286256 
    287257sub list_services { 
    288258    my $node = $_[0] || $FQDN; 
    289     net_write( join( " ", 
    290                      grep( { &has_access ($_); } keys %{$nodes{$node}} ) 
    291                      ) ) 
     259    net_write( 
     260        join( " ", grep( { &has_access($_); } keys %{ $nodes{$node} } ) ) ) 
    292261      if exists $nodes{$node}; 
    293     #print join " ", keys %{$nodes{$node}}; 
    294     net_write ("\n"); 
     262 
     263#print join " ", keys %{$nodes{$node}}; 
     264    net_write("\n"); 
    295265} 
    296266 
    297267sub has_access { 
    298         my $serv   = shift; 
    299         my $host   = $caddr; 
    300         my $rights = &get_var_arr (\%sconf, $serv, 'allow_deny'); 
    301  
    302         unless (@{$rights}) 
    303         { 
    304                 return 1; 
    305         } 
    306         print STDERR "DEBUG: Checking access: $host;$serv;\n" if $DEBUG; 
    307         foreach my $ruleset (@{$rights}) 
    308         { 
    309                 foreach my $rule (@{$ruleset}) 
    310                 { 
    311                         logger ("DEBUG: Checking access: $host;$serv;". $rule->[0].";".$rule->[1]) if $DEBUG; 
    312                         if ($rule->[1] eq "tls" and $tls_verified{"verified"}) 
    313                         { # tls 
    314                                 if ($rule->[0] eq "allow") 
    315                                 { 
    316                                         return 1; 
    317                                 } 
    318                                 else 
    319                                 { 
    320                                         return 0; 
    321                                 } 
    322                         } 
     268    my $serv   = shift; 
     269    my $host   = $caddr; 
     270    my $rights = &get_var_arr( \%sconf, $serv, 'allow_deny' ); 
     271 
     272    unless ( @{$rights} ) { 
     273        return 1; 
     274    } 
     275    print STDERR "DEBUG: Checking access: $host;$serv;\n" if $DEBUG; 
     276    foreach my $ruleset ( @{$rights} ) { 
     277        foreach my $rule ( @{$ruleset} ) { 
     278            logger( "DEBUG: Checking access: $host;$serv;" 
     279                  . $rule->[0] . ";" 
     280                  . $rule->[1] ) 
     281              if $DEBUG; 
     282            if ( $rule->[1] eq "tls" and $tls_verified{"verified"} ) {   # tls 
     283                if ( $rule->[0] eq "allow" ) { 
     284                    return 1; 
     285                } else { 
     286                    return 0; 
     287                } 
     288            } 
     289 
    323290#                       elsif ($rule->[1] =~ /\//) 
    324291#                       { # CIDR 
     
    326293#                               return 1; 
    327294#                       } 
    328                         else 
    329                         { # regex 
    330                                 if ($host =~ m($rule->[1])) 
    331                                 { 
    332                                         if ($rule->[0] eq "allow") 
    333                                         { 
    334                                                 return 1; 
    335                                         } 
    336                                         else 
    337                                         { 
    338                                                 return 0; 
    339                                         } 
    340                                 } 
    341                         } 
    342                 } 
    343         } 
    344         return 1; 
    345 
     295            else {    # regex 
     296                if ( $host =~ m($rule->[1]) ) { 
     297                    if ( $rule->[0] eq "allow" ) { 
     298                        return 1; 
     299                    } else { 
     300                        return 0; 
     301                    } 
     302                } 
     303            } 
     304        } ## end foreach my $rule ( @{$ruleset... 
     305    } ## end foreach my $ruleset ( @{$rights... 
     306    return 1; 
     307} ## end sub has_access 
    346308 
    347309sub logger { 
     310    my $text = shift; 
     311    my @date = localtime(time); 
     312 
     313    chomp($text); 
     314    $text =~ s/\n/\\n/g; 
     315 
     316    printf STDERR ( 
     317        "%d/%02d/%02d-%02d:%02d:%02d [$$] %s\n", 
     318        $date[5] + 1900, 
     319        $date[4] + 1, 
     320        $date[3], $date[2], $date[1], $date[0], $text 
     321    ); 
     322} 
     323 
     324sub reap_children { 
     325    my $child = shift; 
    348326    my $text  = shift; 
    349     my @date  = localtime (time); 
    350  
    351     chomp ($text); 
    352     $text =~ s/\n/\\n/g; 
    353  
    354     printf STDERR ("%d/%02d/%02d-%02d:%02d:%02d [$$] %s\n", $date[5]+1900, $date[4]+1,  
    355             $date[3], $date[2], $date[1], $date[0], $text); 
    356 
    357  
    358 sub reap_children { 
    359   my $child = shift; 
    360   my $text = shift; 
    361   return unless $child; 
    362   if (kill (0, $child))  
    363     {  
    364       net_write ("# timeout pid $child - killing...");  
    365       logger ("Plugin timeout: $text (pid $child)"); 
    366       kill (-1, $child); sleep 2;  
    367       kill (-9, $child); 
    368       net_write ("done\n"); 
    369     }  
     327    return unless $child; 
     328    if ( kill( 0, $child ) ) { 
     329        net_write("# timeout pid $child - killing..."); 
     330        logger("Plugin timeout: $text (pid $child)"); 
     331        kill( -1, $child ); 
     332        sleep 2; 
     333        kill( -9, $child ); 
     334        net_write("done\n"); 
     335    } 
    370336} 
    371337 
    372338sub run_service { 
    373   my ($service,$command,$autoreap) = @_; 
    374   $command ||=""; 
    375   my @lines = ();; 
    376   my $timed_out = 0; 
    377   if ($services{$service} and ($caddr eq "" or &has_access ($service))) { 
    378     my $child = 0; 
    379     my $timeout = get_var (\%sconf, $service, 'timeout'); 
    380     $timeout = $sconf{'timeout'}  
    381         unless defined $timeout and $timeout =~ /^\d+$/; 
    382  
    383     if ($child = open (CHILD, "-|")) { 
    384       eval { 
    385           local $SIG{ALRM} = sub { $timed_out=1; die "$!\n"}; 
    386           alarm($timeout); 
    387           while(<CHILD>) { 
    388             push @lines,$_; 
    389           } 
    390       }; 
    391       if( $timed_out ) { 
    392           reap_children($child, "$service $command: $@"); 
    393           close (CHILD); 
    394           return (); 
    395       } 
    396       unless (close CHILD) 
    397       { 
    398           if ($!) 
    399           { 
    400               # If Net::Server::Fork is currently taking care of reaping, 
    401               # we get false errors. Filter them out. 
    402               unless (defined $autoreap and $autoreap)  
    403               { 
    404                   logger ("Error while executing plugin \"$service\": $!"); 
    405               } 
    406           } 
    407           else 
    408           { 
    409               logger ("Plugin \"$service\" exited with status $?. --@lines--"); 
    410           } 
    411       } 
    412     } 
    413     else { 
    414       if ($child == 0) { 
    415         # New process group... 
    416         POSIX::setsid(); 
    417         # Setting environment 
    418         $sconf{$service}{user}    = &get_var (\%sconf, $service, 'user'); 
    419         $sconf{$service}{group}   = &get_var (\%sconf, $service, 'group'); 
    420         $sconf{$service}{command} = &get_var (\%sconf, $service, 'command'); 
    421         &get_var (\%sconf, $service, 'env', \%{$sconf{$service}{env}}); 
    422          
    423         if ($< == 0) # If root... 
    424         { 
    425                 # Giving up gid egid uid euid 
    426                 my $u  = (defined $sconf{$service}{'user'}? 
    427                         $sconf{$service}{'user'}: 
    428                         $defuser); 
    429                 my $g  = $defgroup; 
    430                 my $gs = "$g $g" . 
    431                         ($sconf{$service}{'group'}?" $sconf{$service}{group}":""); 
     339    my ( $service, $command, $autoreap ) = @_; 
     340    $command ||= ""; 
     341    my @lines     = (); 
     342    my $timed_out = 0; 
     343    if ( $services{$service} and ( $caddr eq "" or &has_access($service) ) ) { 
     344        my $child = 0; 
     345        my $timeout = get_var( \%sconf, $service, 'timeout' ); 
     346        $timeout = $sconf{'timeout'} 
     347          unless defined $timeout and $timeout =~ /^\d+$/; 
     348 
     349        if ( $child = open( CHILD, "-|" ) ) { 
     350            eval { 
     351                local $SIG{ALRM} = sub { $timed_out = 1; die "$!\n" }; 
     352                alarm($timeout); 
     353                while (<CHILD>) { 
     354                    push @lines, $_; 
     355                } 
     356            }; 
     357            if ($timed_out) { 
     358                reap_children( $child, "$service $command: $@" ); 
     359                close(CHILD); 
     360                return (); 
     361            } 
     362            unless ( close CHILD ) { 
     363                if ($!) { 
     364 
     365# If Net::Server::Fork is currently taking care of reaping, 
     366# we get false errors. Filter them out. 
     367                    unless ( defined $autoreap and $autoreap ) { 
     368                        logger( 
     369                            "Error while executing plugin \"$service\": $!"); 
     370                    } 
     371                } else { 
     372                    logger( 
     373"Plugin \"$service\" exited with status $?. --@lines--" 
     374                    ); 
     375                } 
     376            } 
     377        } ## end if ( $child = open( CHILD... 
     378        else { 
     379            if ( $child == 0 ) { 
     380 
     381# New process group... 
     382                POSIX::setsid(); 
     383 
     384# Setting environment 
     385                $sconf{$service}{user} = 
     386                  &get_var( \%sconf, $service, 'user' ); 
     387                $sconf{$service}{group} = 
     388                  &get_var( \%sconf, $service, 'group' ); 
     389                $sconf{$service}{command} = 
     390                  &get_var( \%sconf, $service, 'command' ); 
     391                &get_var( \%sconf, $service, 'env', 
     392                    \%{ $sconf{$service}{env} } ); 
     393 
     394                if ( $< == 0 )    # If root... 
     395                { 
     396 
     397# Giving up gid egid uid euid 
     398                    my $u = ( 
     399                        defined $sconf{$service}{'user'} 
     400                        ? $sconf{$service}{'user'} 
     401                        : $defuser 
     402                    ); 
     403                    my $g  = $defgroup; 
     404                    my $gs = "$g $g" 
     405                      . ( 
     406                        $sconf{$service}{'group'} 
     407                        ? " $sconf{$service}{group}" 
     408                        : "" 
     409                      ); 
    432410 
    433411#               net_write ("# Want to run as euid/egid $u/$g\n") if $DEBUG; 
    434412 
    435                $( = $g    unless $g == 0; 
    436                $) = $gs  unless $g == 0; 
    437                $< = $u    unless $u == 0; 
    438                $> = $u    unless $u == 0; 
    439  
    440                 if ($> != $u or $g != (split (' ', $)))[0]) 
    441                 { 
     413                    $( = $g  unless $g == 0; 
     414                    $) = $gs unless $g == 0; 
     415                    $< = $u  unless $u == 0; 
     416                    $> = $u  unless $u == 0; 
     417 
     418                    if ( $> != $u or $g != ( split( ' ', $) ) )[0] ) { 
     419 
    442420#                       net_write ("# Can't drop privileges. Bailing out. (wanted uid=", 
    443421#                           ($sconf{$service}{'user'} || $defuser), " gid=\"", 
    444 #                           $gs, "\"($g), got uid=$> gid=\"$)\"(",  
     422#                           $gs, "\"($g), got uid=$> gid=\"$)\"(", 
    445423#                           (split (' ', $)))[0], ").\n"); 
    446                         logger ("Plugin \"$service\" Can't drop privileges. ". 
    447                             "Bailing out. (wanted uid=". 
    448                             ($sconf{$service}{'user'} || $defuser). " gid=\"". 
    449                             $gs. "\"($g), got uid=$> gid=\"$)\"(".  
    450                             (split (' ', $)))[0]. ").\n"); 
    451                         exit 1; 
    452                 } 
    453         } 
    454 #       net_write ("# Running as uid/gid/euid/egid $</$(/$>/$)\n") if $DEBUG; 
    455         if (!&check_perms ("$servicedir/$service")) 
    456         { 
     424                        logger( "Plugin \"$service\" Can't drop privileges. " 
     425                              . "Bailing out. (wanted uid=" 
     426                              . ( $sconf{$service}{'user'} || $defuser ) 
     427                              . " gid=\"" 
     428                              . $gs 
     429                              . "\"($g), got uid=$> gid=\"$)\"(" 
     430                              . ( split( ' ', $) ) )[0] 
     431                              . ").\n" ); 
     432                        exit 1; 
     433                    } 
     434                } ## end if ( $< == 0 ) 
     435                 #      net_write ("# Running as uid/gid/euid/egid $</$(/$>/$)\n") if $DEBUG; 
     436                if ( !&check_perms("$servicedir/$service") ) { 
     437 
    457438#           net_write ("# Error: unsafe permissions. Bailing out."); 
    458            logger ("Error: unsafe permissions. Bailing out."); 
    459            exit 2; 
    460        
    461  
    462        # Setting environment... 
    463         if (exists $sconf{$service}{'env'} and 
    464                        defined $sconf{$service}{'env'}
    465        
    466             foreach my $key (keys %{$sconf{$service}{'env'}}) 
    467             { 
     439                    logger("Error: unsafe permissions. Bailing out."); 
     440                    exit 2; 
     441               
     442 
     443# Setting environment... 
     444                if ( exists $sconf{$service}{'env'} 
     445                    and defined $sconf{$service}{'env'}
     446               
     447                    foreach my $key ( keys %{ $sconf{$service}{'env'} } ) { 
     448 
    468449#               net_write ("# Setting environment $key=$sconf{$service}{env}{$key}\n") if $DEBUG; 
    469                 $ENV{"$key"} = $sconf{$service}{'env'}{$key}; 
    470             } 
    471         } 
    472         if (exists $sconf{$service}{'command'} and  
    473                 defined $sconf{$service}{'command'}) 
    474         { 
    475             my @run = (); 
    476             foreach my $t (@{$sconf{$service}{'command'}}) 
    477             { 
    478                 if ($t =~ /^%c$/) 
    479                 { 
    480                     push (@run, "$servicedir/$service", $command); 
    481                 } 
    482                 else 
    483                 { 
    484                     push (@run, $t); 
    485                 } 
    486             } 
    487             print STDERR "# About to run \"", join (' ', @run), "\"\n" if $DEBUG; 
     450                        $ENV{"$key"} = $sconf{$service}{'env'}{$key}; 
     451                    } 
     452                } 
     453                if ( exists $sconf{$service}{'command'} 
     454                    and defined $sconf{$service}{'command'} ) 
     455                { 
     456                    my @run = (); 
     457                    foreach my $t ( @{ $sconf{$service}{'command'} } ) { 
     458                        if ( $t =~ /^%c$/ ) { 
     459                            push( @run, "$servicedir/$service", $command ); 
     460                        } else { 
     461                            push( @run, $t ); 
     462                        } 
     463                    } 
     464                    print STDERR "# About to run \"", join( ' ', @run ), 
     465                      "\"\n" 
     466                      if $DEBUG; 
     467 
    488468#           net_write ("# About to run \"", join (' ', @run), "\"\n") if $DEBUG; 
    489            exec (@run) if @run; 
    490         } 
    491         else 
    492         { 
     469                    exec(@run) if @run; 
     470                } ## end if ( exists $sconf{$service... 
     471                else { 
     472 
    493473#           net_write ("# Execing...\n") if $DEBUG; 
    494             exec ("$servicedir/$service", $command); 
    495         } 
    496       } 
    497       else { 
     474                    exec( "$servicedir/$service", $command ); 
     475                } 
     476            } ## end if ( $child == 0 ) 
     477            else { 
     478 
    498479#       net_write ("# Unable to fork.\n"); 
    499        logger ("Unable to fork."); 
    500      
    501     } 
    502     wait; 
    503     alarm(0); 
    504   } 
    505   else { 
    506     net_write ("# Unknown service\n"); 
    507  
    508   chomp @lines; 
    509   return (@lines); 
    510 } 
     480                logger("Unable to fork."); 
     481           
     482        } ## end else [ if ( $child = open( CHILD... 
     483        wait; 
     484        alarm(0); 
     485    } ## end if ( $services{$service... 
     486    else { 
     487        net_write("# Unknown service\n"); 
     488   
     489    chomp @lines; 
     490    return (@lines); 
     491} ## end sub run_service 
    511492 
    512493sub process_request { 
    513   my $self = shift; 
    514   $caddr = $self->{server}->{peeraddr}; 
    515   $0 .= " [$caddr]"; 
    516   net_write ("# munin node at $FQDN\n"); 
    517   local $SIG{ALRM} = sub { logger ("Connection timed out."); die "timeout" }; 
    518   alarm($sconf{'timeout'}); 
    519   while (defined ($_ = net_read())) { 
    520     alarm($sconf{'timeout'}); 
    521     chomp; 
    522     logger ("DEBUG: Running command \"$_\".") if $DEBUG; 
    523     if (/^list\s*([0-9a-zA-Z\.\-]+)?/i) { 
    524       &list_services($1); 
    525     } 
    526     elsif (/^quit/i || /^\./) { 
    527       exit 1; 
    528     } 
    529     elsif (/^version/i) { 
    530       &show_version; 
    531         } 
    532     elsif (/^nodes/i) { 
    533       &show_nodes; 
    534     } 
    535     elsif (/^fetch\s?(\S*)/i) { 
    536       print_service (&run_service($1))  
    537     } 
    538     elsif (/^config\s?(\S*)/i) { 
    539       print_service (&run_service($1,"config")); 
    540     }  
    541     elsif (/^starttls\s*$/i) { 
    542       my $mode; 
    543       my $key; 
    544       my $cert; 
    545       my $depth; 
    546       $key = $cert = &get_var (\%sconf, "tls_pem"); 
    547       $key = &get_var (\%sconf, "tls_private_key") 
    548           unless defined $key; 
    549       $key = "@@CONFDIR@@/munin-node.pem" unless defined $key; 
    550       $cert = &get_var (\%sconf, "tls_certificate") 
    551           unless defined $cert; 
    552       $cert = "@@CONFDIR@@/munin-node.pem" unless defined $cert; 
    553       $mode = &get_var (\%sconf, 'tls'); 
    554       $mode = "auto" unless defined $mode and length $mode; 
    555       $depth = &get_var (\%sconf, 'tls_verify_depth'); 
    556       $depth = 5 unless defined $depth; 
    557       start_tls ($mode, $cert, $key, 
    558               &get_var (\%sconf, 'tls_verify_certificate'), 
    559               $depth 
    560               ); 
    561       logger ("DEBUG: Returned from starttls.") if $DEBUG; 
    562     } 
    563     else  { 
    564       net_write ("# Unknown command. Try list, nodes, config, fetch, version or quit\n"); 
    565     } 
    566   } 
    567 
    568  
    569 sub net_read  
    570 
    571     if (defined $tls) 
    572     { 
    573         eval { $_ = Net::SSLeay::read($tls); }; 
    574         my $err = &Net::SSLeay::print_errs(); 
    575         if (defined $err and length $err) 
    576         { 
    577             logger ("TLS Warning in net_read: $err"); 
    578         } 
    579     } 
    580     else 
    581     { 
    582         $_ = <STDIN>; 
    583     } 
    584     logger ("DEBUG: < $_") if $DEBUG; 
     494    my $self = shift; 
     495    $caddr = $self->{server}->{peeraddr}; 
     496    $0 .= " [$caddr]"; 
     497    net_write("# munin node at $FQDN\n"); 
     498    local $SIG{ALRM} = sub { logger("Connection timed out."); die "timeout" }; 
     499    alarm( $sconf{'timeout'} ); 
     500    while ( defined( $_ = net_read() ) ) { 
     501        alarm( $sconf{'timeout'} ); 
     502        chomp; 
     503        logger("DEBUG: Running command \"$_\".") if $DEBUG; 
     504        if (/^list\s*([0-9a-zA-Z\.\-]+)?/i) { 
     505            &list_services($1); 
     506        } elsif ( /^quit/i || /^\./ ) { 
     507            exit 1; 
     508        } elsif (/^version/i) { 
     509            &show_version; 
     510        } elsif (/^nodes/i) { 
     511            &show_nodes; 
     512        } elsif (/^fetch\s?(\S*)/i) { 
     513            print_service( &run_service($1) ); 
     514        } elsif (/^config\s?(\S*)/i) { 
     515            print_service( &run_service( $1, "config" ) ); 
     516        } elsif (/^starttls\s*$/i) { 
     517            my $mode; 
     518            my $key; 
     519            my $cert; 
     520            my $depth; 
     521            $key = $cert = &get_var( \%sconf, "tls_pem" ); 
     522            $key = &get_var( \%sconf, "tls_private_key" ) 
     523              unless defined $key; 
     524            $key = "@@CONFDIR@@/munin-node.pem" unless defined $key; 
     525            $cert = &get_var( \%sconf, "tls_certificate" ) 
     526 
     527              unless defined $cert; 
     528            $cert = "@@CONFDIR@@/munin-node.pem" unless defined $cert; 
     529            $mode = &get_var( \%sconf, 'tls' ); 
     530            $mode = "auto" unless defined $mode and length $mode; 
     531            $depth = &get_var( \%sconf, 'tls_verify_depth' ); 
     532            $depth = 5 unless defined $depth; 
     533            start_tls( $mode, $cert, $key, 
     534                &get_var( \%sconf, 'tls_verify_certificate' ), $depth ); 
     535            logger("DEBUG: Returned from starttls.") if $DEBUG; 
     536        } ## end elsif (/^starttls\s*$/i) 
     537        else { 
     538            net_write( 
     539"# Unknown command. Try list, nodes, config, fetch, version or quit\n" 
     540            ); 
     541        } 
     542    } ## end while ( defined( $_ = net_read... 
     543} ## end sub process_request 
     544 
     545sub net_read { 
     546    if ( defined $tls ) { 
     547        eval { $_ = Net::SSLeay::read($tls); }; 
     548        my $err = &Net::SSLeay::print_errs(); 
     549        if ( defined $err and length $err ) { 
     550            logger("TLS Warning in net_read: $err"); 
     551        } 
     552    } else { 
     553        $_ = <STDIN>; 
     554    } 
     555    logger("DEBUG: < $_") if $DEBUG; 
    585556    return $_; 
    586557} 
    587558 
    588 sub net_write  
    589 
     559sub net_write { 
    590560    my $text = shift; 
    591     logger ("DEBUG: > $text") if $DEBUG; 
    592     if (defined $tls) 
    593     { 
    594         eval { Net::SSLeay::write ($tls, $text); }; 
    595         my $err = &Net::SSLeay::print_errs(); 
    596         if (defined $err and length $err) 
    597         { 
    598             logger ("TLS Warning in net_write: $err"); 
    599         } 
    600     } 
    601     else 
    602     { 
    603         print STDOUT $text; 
    604     } 
    605 
    606  
    607 sub tls_verify_callback  
    608 
    609     my ($ok, $subj_cert, $issuer_cert, $depth,  
    610             $errorcode, $arg, $chain) = @_; 
     561    logger("DEBUG: > $text") if $DEBUG; 
     562    if ( defined $tls ) { 
     563        eval { Net::SSLeay::write( $tls, $text ); }; 
     564        my $err = &Net::SSLeay::print_errs(); 
     565        if ( defined $err and length $err ) { 
     566            logger("TLS Warning in net_write: $err"); 
     567        } 
     568    } else { 
     569        print STDOUT $text; 
     570    } 
     571
     572 
     573sub tls_verify_callback { 
     574    my ( $ok, $subj_cert, $issuer_cert, $depth, $errorcode, $arg, $chain ) = 
     575      @_; 
    611576 
    612577    $tls_verified{"level"}++; 
    613578 
    614     if ($ok and $tls_verified{"level"} <= $tls_verified{"required_depth"}) 
    615     { 
    616         $tls_verified{"verified"} = 1; 
    617         logger ("TLS Notice: Verified certificate.") if $DEBUG; 
    618         return 1; # accept 
    619     } 
    620  
    621     return 1; # accept anyway 
    622 
    623  
    624 sub start_tls  
    625 
     579    if ( $ok and $tls_verified{"level"} <= $tls_verified{"required_depth"} ) { 
     580        $tls_verified{"verified"} = 1; 
     581        logger("TLS Notice: Verified certificate.") if $DEBUG; 
     582        return 1;    # accept 
     583    } 
     584 
     585    return 1;        # accept anyway 
     586
     587 
     588sub start_tls { 
    626589    my $tls_paranoia = shift; 
    627590    my $tls_cert     = shift; 
     
    634597    my $local_key = 0; 
    635598 
    636     %tls_verified = ( "level" => 0, "cert" => "", "verified" => 0, "required_depth" => $tls_vdepth ); 
    637  
    638     if ($tls_paranoia eq "disabled") 
    639     { 
    640         logger ("TLS Notice: Refusing TLS request from peer."); 
    641         net_write ("TLS NOT AVAILABLE\n"); 
    642         return 0 
     599    %tls_verified = ( 
     600        "level"          => 0, 
     601        "cert"           => "", 
     602        "verified"       => 0, 
     603        "required_depth" => $tls_vdepth 
     604    ); 
     605 
     606    if ( $tls_paranoia eq "disabled" ) { 
     607        logger("TLS Notice: Refusing TLS request from peer."); 
     608        net_write("TLS NOT AVAILABLE\n"); 
     609        return 0; 
    643610    } 
    644611 
    645612    logger("Enabling TLS.") if $DEBUG; 
    646     if (! eval "require Net::SSLeay;") 
    647     { 
    648         if ($tls_paranoia eq "auto") 
    649         { 
    650             logger ("Notice: TLS requested by peer, but Net::SSLeay unavailable."); 
    651             return 0; 
    652         } 
    653         else # tls really required 
    654         { 
    655             logger ("Fatal: TLS enabled but Net::SSLeay unavailable."); 
    656             exit 0; 
    657         } 
    658     } 
    659  
    660     # Init SSLeay 
     613    if ( !eval "require Net::SSLeay;" ) { 
     614        if ( $tls_paranoia eq "auto" ) { 
     615            logger( 
     616                "Notice: TLS requested by peer, but Net::SSLeay unavailable." 
     617            ); 
     618            return 0; 
     619        } else    # tls really required 
     620        { 
     621            logger("Fatal: TLS enabled but Net::SSLeay unavailable."); 
     622            exit 0; 
     623        } 
     624    } 
     625 
     626# Init SSLeay 
    661627    Net::SSLeay::load_error_strings(); 
    662628    Net::SSLeay::SSLeay_add_ssl_algorithms(); 
    663629    Net::SSLeay::randomize(); 
    664630    $ctx = Net::SSLeay::CTX_new(); 
    665     if (!$ctx) 
    666     { 
    667         logger ("TLS Error: Could not create SSL_CTX: " . &Net::SSLeay::print_errs()); 
    668         return 0; 
    669     } 
    670  
    671     # Tune a few things... 
    672     if (Net::SSLeay::CTX_set_options($ctx, &Net::SSLeay::OP_ALL)) 
    673     { 
    674         logger ("TLS Error: Could not set SSL_CTX options: " . &Net::SSLeay::print_errs()); 
    675         return 0; 
    676     } 
    677  
    678     # Should we use a private key? 
    679     if (-e $tls_priv or $tls_paranoia eq "paranoid") 
    680     { 
    681         if (defined $tls_priv and length $tls_priv) 
    682         { 
    683             if (!Net::SSLeay::CTX_use_PrivateKey_file($ctx, $tls_priv,  
    684                     &Net::SSLeay::FILETYPE_PEM)) 
    685             { 
    686                 logger ("TLS Notice: Problem occured when trying to read file with private key \"$tls_priv\": ".&Net::SSLeay::print_errs().". Continuing without private key."); 
    687             } 
    688             else 
    689             { 
    690                 $local_key = 1; 
    691             } 
    692         } 
    693     } 
    694     else 
    695     { 
    696         logger ("TLS Notice: No key file \"$tls_priv\". Continuing without private key."); 
    697     } 
    698  
    699     # How about a certificate? 
    700     if (-e $tls_cert) 
    701     { 
    702         if (defined $tls_cert and length $tls_cert) 
    703         { 
    704             if (!Net::SSLeay::CTX_use_certificate_file($ctx, $tls_cert,  
    705                     &Net::SSLeay::FILETYPE_PEM)) 
    706             { 
    707                 logger ("TLS Notice: Problem occured when trying to read file with certificate \"$tls_cert\": ".&Net::SSLeay::print_errs().". Continuing without certificate."); 
    708             } 
    709         } 
    710     } 
    711     else 
    712     { 
    713         logger ("TLS Notice: No certificate file \"$tls_cert\". Continuing without certificate."); 
    714     } 
    715  
    716     # Tell the other side that we're able to talk TLS 
    717     if ($local_key) 
    718     { 
     631    if ( !$ctx ) { 
     632        logger( "TLS Error: Could not create SSL_CTX: " 
     633              . &Net::SSLeay::print_errs() ); 
     634        return 0; 
     635    } 
     636 
     637# Tune a few things... 
     638    if ( Net::SSLeay::CTX_set_options( $ctx, &Net::SSLeay::OP_ALL ) ) { 
     639        logger( "TLS Error: Could not set SSL_CTX options: " 
     640              . &Net::SSLeay::print_errs() ); 
     641        return 0; 
     642    } 
     643 
     644# Should we use a private key? 
     645    if ( -e $tls_priv or $tls_paranoia eq "paranoid" ) { 
     646        if ( defined $tls_priv and length $tls_priv ) { 
     647            if ( 
     648                !Net::SSLeay::CTX_use_PrivateKey_file( 
     649                    $ctx, $tls_priv, &Net::SSLeay::FILETYPE_PEM 
     650                ) ) 
     651            { 
     652                logger( 
     653"TLS Notice: Problem occured when trying to read file with private key \"$tls_priv\": " 
     654                      . &Net::SSLeay::print_errs() 
     655                      . ". Continuing without private key." ); 
     656            } else { 
     657                $local_key = 1; 
     658            } 
     659        } 
     660    } ## end if ( -e $tls_priv or $tls_paranoia... 
     661    else { 
     662        logger( 
     663"TLS Notice: No key file \"$tls_priv\". Continuing without private key." 
     664        ); 
     665    } 
     666 
     667# How about a certificate? 
     668    if ( -e $tls_cert ) { 
     669        if ( defined $tls_cert and length $tls_cert ) { 
     670            if ( 
     671                !Net::SSLeay::CTX_use_certificate_file( 
     672                    $ctx, $tls_cert, &Net::SSLeay::FILETYPE_PEM 
     673                ) ) 
     674            { 
     675                logger( 
     676"TLS Notice: Problem occured when trying to read file with certificate \"$tls_cert\": " 
     677                      . &Net::SSLeay::print_errs() 
     678                      . ". Continuing without certificate." ); 
     679            } 
     680        } 
     681    } else { 
     682        logger( 
     683"TLS Notice: No certificate file \"$tls_cert\". Continuing without certificate." 
     684        ); 
     685    } 
     686 
     687# Tell the other side that we're able to talk TLS 
     688    if ($local_key) { 
    719689        print "TLS OK\n"; 
    720     } 
    721     else 
    722     { 
     690    } else { 
    723691        print "TLS MAYBE\n"; 
    724692    } 
    725693 
    726     # Now let's define our requirements of the node 
     694# Now let's define our requirements of the node 
    727695    $tls_vdepth = 5 unless defined $tls_vdepth; 
    728     Net::SSLeay::CTX_set_verify_depth ($ctx, $tls_vdepth); 
     696    Net::SSLeay::CTX_set_verify_depth( $ctx, $tls_vdepth ); 
    729697    $err = &Net::SSLeay::print_errs(); 
    730     if (defined $err and length $err) 
    731     { 
    732         logger ("TLS Warning in set_verify_depth: $err"); 
    733     } 
    734     Net::SSLeay::CTX_set_verify ($ctx, &Net::SSLeay::VERIFY_PEER, \&tls_verify_callback); 
     698    if ( defined $err and length $err ) { 
     699        logger("TLS Warning in set_verify_depth: $err"); 
     700    } 
     701    Net::SSLeay::CTX_set_verify( $ctx, &Net::SSLeay::VERIFY_PEER, 
     702        \&tls_verify_callback ); 
    735703    $err = &Net::SSLeay::print_errs(); 
    736     if (defined $err and length $err) 
    737     { 
    738         logger ("TLS Warning in set_verify: $err"); 
    739     } 
    740  
    741     # Create the local tls object 
    742     if (! ($tls = Net::SSLeay::new($ctx))) 
    743     { 
    744         logger ("TLS Error: Could not create TLS: " . &Net::SSLeay::print_errs()); 
    745         return 0; 
    746     } 
    747     if ($DEBUG) 
    748     { 
    749         my $i = 0; 
    750         my $p = ''; 
    751         my $cipher_list = 'Cipher list: '; 
    752         $p=Net::SSLeay::get_cipher_list($tls,$i); 
    753         $cipher_list .= $p if $p; 
    754         do { 
    755             $i++; 
    756             $cipher_list .= ', ' . $p if $p; 
    757             $p=Net::SSLeay::get_cipher_list($tls,$i); 
    758         } while $p; 
     704    if ( defined $err and length $err ) { 
     705        logger("TLS Warning in set_verify: $err"); 
     706    } 
     707 
     708# Create the local tls object 
     709    if ( !( $tls = Net::SSLeay::new($ctx) ) ) { 
     710        logger( "TLS Error: Could not create TLS: " 
     711              . &Net::SSLeay::print_errs() ); 
     712        return 0; 
     713    } 
     714    if ($DEBUG) { 
     715        my $i           = 0; 
     716        my $p           = ''; 
     717        my $cipher_list = 'Cipher list: '; 
     718        $p = Net::SSLeay::get_cipher_list( $tls, $i ); 
     719        $cipher_list .= $p if $p; 
     720        do { 
     721            $i++; 
     722            $cipher_list .= ', ' . $p if $p; 
     723            $p = Net::SSLeay::get_cipher_list( $tls, $i ); 
     724        } while $p; 
    759725        $cipher_list .= '\n'; 
    760        logger ("TLS Notice: Available cipher list: $cipher_list."); 
    761     } 
    762  
    763     # Redirect stdout/stdin to the TLS 
    764     Net::SSLeay::set_rfd($tls, fileno(STDIN)); 
     726        logger("TLS Notice: Available cipher list: $cipher_list."); 
     727    } 
     728 
     729# Redirect stdout/stdin to the TLS 
     730    Net::SSLeay::set_rfd( $tls, fileno(STDIN) ); 
    765731    $err = &Net::SSLeay::print_errs(); 
    766     if (defined $err and length $err) 
    767     { 
    768         logger ("TLS Warning in set_rfd: $err"); 
    769     } 
    770     Net::SSLeay::set_wfd($tls, fileno(STDOUT)); 
     732    if ( defined $err and length $err ) { 
     733        logger("TLS Warning in set_rfd: $err"); 
     734    } 
     735    Net::SSLeay::set_wfd( $tls, fileno(STDOUT) ); 
    771736    $err = &Net::SSLeay::print_errs(); 
    772     if (defined $err and length $err) 
    773     { 
    774         logger ("TLS Warning in set_wfd: $err"); 
    775     } 
    776  
    777     # Try to negotiate the tls connection 
     737    if ( defined $err and length $err ) { 
     738        logger("TLS Warning in set_wfd: $err"); 
     739    } 
     740 
     741# Try to negotiate the tls connection 
    778742    my $res; 
    779     if ($local_key) 
    780     { 
     743    if ($local_key) { 
    781744        $res = Net::SSLeay::accept($tls); 
    782     } 
    783     else 
    784     { 
     745    } else { 
    785746        $res = Net::SSLeay::connect($tls); 
    786747    } 
    787748    $err = &Net::SSLeay::print_errs(); 
    788     if (defined $err and length $err) 
    789     { 
    790         logger ("TLS Error: Could not enable TLS: " . $err); 
    791         Net::SSLeay::free ($tls); 
    792         Net::SSLeay::CTX_free ($ctx); 
    793         $tls = undef; 
    794     } 
    795     elsif (!$tls_verified{"verified"} and $tls_paranoia eq "paranoid") 
    796     { 
    797         logger ("TLS Error: Could not verify CA: " . Net::SSLeay::dump_peer_certificate($tls)); 
    798         Net::SSLeay::free ($tls); 
    799         Net::SSLeay::CTX_free ($ctx); 
    800         $tls = undef; 
    801     } 
    802     else 
    803     { 
    804         logger ("TLS Notice: TLS enabled."); 
    805         logger ("TLS Notice: Cipher `" . Net::SSLeay::get_cipher($tls) . "'."); 
    806         $tls_verified{"cert"} = Net::SSLeay::dump_peer_certificate($tls); 
    807         logger ("TLS Notice: client cert: " .$tls_verified{"cert"}); 
     749    if ( defined $err and length $err ) { 
     750        logger( "TLS Error: Could not enable TLS: " . $err ); 
     751        Net::SSLeay::free($tls); 
     752        Net::SSLeay::CTX_free($ctx); 
     753        $tls = undef; 
     754    } elsif ( !$tls_verified{"verified"} and $tls_paranoia eq "paranoid" ) { 
     755        logger( "TLS Error: Could not verify CA: " 
     756              . Net::SSLeay::dump_peer_certificate($tls) ); 
     757        Net::SSLeay::free($tls); 
     758        Net::SSLeay::CTX_free($ctx); 
     759        $tls = undef; 
     760    } else { 
     761        logger("TLS Notice: TLS enabled."); 
     762        logger( 
     763            "TLS Notice: Cipher `" . Net::SSLeay::get_cipher($tls) . "'." ); 
     764        $tls_verified{"cert"} = Net::SSLeay::dump_peer_certificate($tls); 
     765        logger( "TLS Notice: client cert: " . $tls_verified{"cert"} ); 
    808766    } 
    809767 
    810768    return $tls; 
    811 
    812  
    813 sub get_uid 
    814 
     769} ## end sub start_tls 
     770 
     771sub get_uid { 
    815772    my $user = shift; 
    816     return undef if (!defined $user); 
    817  
    818     if ($user !~ /\d/) 
    819     { 
    820         $user = getpwnam ($user); 
     773    return undef if ( !defined $user ); 
     774 
     775    if ( $user !~ /\d/ ) { 
     776        $user = getpwnam($user); 
    821777    } 
    822778    return $user; 
    823779} 
    824780 
    825 sub get_gid 
    826 
     781sub get_gid { 
    827782    my $group = shift; 
    828     return undef if (!defined $group); 
    829  
    830     if ($group !~ /\d/) 
    831     { 
    832         $group = getgrnam ($group); 
     783    return undef if ( !defined $group ); 
     784 
     785    if ( $group !~ /\d/ ) { 
     786        $group = getgrnam($group); 
    833787    } 
    834788    return $group; 
    835789} 
    836790 
    837 sub load_auth_file  
    838 
    839     my ($dir, $file, $sconf) = @_; 
     791sub load_auth_file { 
     792    my ( $dir, $file, $sconf ) = @_; 
    840793    my $service = $file; 
    841794 
    842     if (!defined $dir or !defined $file or !defined $sconf) 
    843     { 
    844         return undef; 
    845     } 
    846  
    847     return undef if (!&check_perms ($dir)); 
    848     return undef if (!&check_perms ("$dir/$file")); 
    849  
    850     if (!open (IN, "$dir/$file")) 
    851     { 
    852         warn "Could not open file \"$dir/$file\" for reading ($!), skipping plugin\n"; 
    853         return undef; 
    854     } 
    855     while (<IN>) 
    856     { 
    857         chomp; 
    858         s/#.*$//; 
    859         next unless /\S/; 
    860         s/\s+$//g; 
    861         net_write ("DEBUG: Config: $service: $_\n") if $DEBUG; 
    862         if (/^\s*\[([^\]]+)\]\s*$/) 
    863         { 
    864             $service = $1; 
    865         } 
    866         elsif (/^\s*user\s+(\S+)\s*$/) 
    867         { 
    868             my $tmpid = $1; 
    869             $sconf->{$service}{'user'} = &get_uid ($tmpid); 
    870             net_write ("DEBUG: Config: $service->uid = ", $sconf->{$service}{'user'}, "\n") if $DEBUG; 
    871             if (!defined $sconf->{$service}{'user'}) 
    872             { 
    873                 warn "User \"$tmpid\" in configuration file \"$dir/$file\" nonexistant. Skipping plugin."; 
    874                 return undef; 
    875             } 
    876         } 
    877         elsif (/^\s*group\s+(.+)\s*$/) 
    878         { 
    879             my $tmpid = $1; 
    880             foreach my $group (split /\s*,\s*/, $tmpid) 
    881             { 
    882                 my $optional = 0; 
    883  
    884                 if ($group =~ /^\(([^)]+)\)$/) 
    885                 { 
    886                     $optional = 1; 
    887                     $group = $1; 
    888                 } 
    889  
    890                 my $g = &get_gid ($group); 
    891                 net_write ("DEBUG: Config: $service->gid = ". $sconf->{$service}{'group'}. "\n") 
    892                         if $DEBUG and defined $sconf->{$service}{'group'}; 
    893                 if (!defined $g and !$optional) 
    894                 { 
    895                     warn "Group \"$group\" in configuration file \"$dir/$file\" nonexistant. Skipping plugin."; 
    896                     return undef; 
    897                 } 
    898                 elsif (!defined $g and $optional) 
    899                 { 
    900                     net_write ("DEBUG: Skipping \"$group\" (optional).\n") if $DEBUG; 
    901                     next; 
    902                 } 
    903                 if (!defined $sconf->{$service}{'group'}) 
    904                 { 
    905                     $sconf->{$service}{'group'} = $g; 
    906                 } 
    907                 else 
    908                 { 
    909                     $sconf->{$service}{'group'} .= " $g"; 
    910                 } 
    911             } 
    912         } 
    913         elsif (/^\s*command\s+(.+)\s*$/) 
    914         { 
    915             @{$sconf->{$service}{'command'}} = split (/\s+/, $1); 
    916         } 
    917         elsif (/^\s*host_name\s+(.+)\s*$/) 
    918         { 
    919             $sconf->{$service}{'host_name'} = $1; 
    920         } 
    921         elsif (/^\s*timeout\s+(\d+)\s*$/) 
    922         { 
    923             $sconf->{$service}{'timeout'} = $1; 
    924             net_write ("DEBUG: $service: setting timeout to $1\n") 
    925                 if $DEBUG; 
    926         } 
    927         elsif (/^\s*(allow)\s+(.+)\s*$/ or /^\s*(deny)\s+(.+)\s*$/) 
    928         { 
    929             push (@{$sconf->{$service}{'allow_deny'}}, [$1, $2]); 
    930                 print STDERR "DEBUG: Pushing allow_deny: $1, $2\n" if $DEBUG; 
    931         } 
    932         elsif (/^\s*env\s+([^=\s]+)\s*=\s*(.+)$/) 
    933         { 
    934             # $sconf->{$service}{'env'}{$1} = $2; 
    935             # net_write ("Saving $service->env->$1 = $2...\n") if $DEBUG; 
    936             warn "Warning: Deprecated format in \"$dir/$file\" under \"[$service]\" (\"env $1=$2\" should be rewritten to \"env.$1 $2. Ignored.\")."; 
    937         } 
    938         elsif (/^\s*env\.(\S+)\s+(.+)$/) 
    939         { 
    940             $sconf->{$service}{'env'}{$1} = $2; 
    941             net_write ("Saving $service->env->$1 = $2...\n") if $DEBUG; 
    942         } 
    943         elsif (/^\s*(\w+)\s+(.+)$/) 
    944         { 
    945             # $sconf->{$service}{'env'}{"lrrd_$1"} = $2; 
    946             # net_write ("Saving $service->env->lrrd_$1 = $2...\n") if $DEBUG; 
    947             warn "Warning: Deprecated format in \"$dir/$file\" under \"[$service]\" (\"$1 $2\" should be rewritten to \"env.$1 $2. Ignored.\")."; 
    948         } 
    949         elsif (/\S/) 
    950         { 
    951             warn "Warning: Unknown config option in \"$dir/$file\" under \"[$service]\": $_"; 
    952         } 
    953  
    954     } 
    955     close (IN); 
     795    if ( !defined $dir or !defined $file or !defined $sconf ) { 
     796        return undef; 
     797    } 
     798 
     799    return undef if ( !&check_perms($dir) ); 
     800    return undef if ( !&check_perms("$dir/$file") ); 
     801 
     802    if ( !open( IN, "$dir/$file" ) ) { 
     803        warn 
     804"Could not open file \"$dir/$file\" for reading ($!), skipping plugin\n"; 
     805        return undef; 
     806    } 
     807    while (<IN>) { 
     808        chomp; 
     809        s/#.*$//; 
     810        next unless /\S/; 
     811        s/\s+$//g; 
     812        net_write("DEBUG: Config: $service: $_\n") if $DEBUG; 
     813        if (/^\s*\[([^\]]+)\]\s*$/) { 
     814            $service = $1; 
     815        } elsif (/^\s*user\s+(\S+)\s*$/) { 
     816            my $tmpid = $1; 
     817            $sconf->{$service}{'user'} = &get_uid($tmpid); 
     818            net_write( "DEBUG: Config: $service->uid = ", 
     819                $sconf->{$service}{'user'}, "\n" ) 
     820              if $DEBUG; 
     821            if ( !defined $sconf->{$service}{'user'} ) { 
     822                warn 
     823"User \"$tmpid\" in configuration file \"$dir/$file\" nonexistant. Skipping plugin."; 
     824                return undef; 
     825            } 
     826        } elsif (/^\s*group\s+(.+)\s*$/) { 
     827            my $tmpid = $1; 
     828            foreach my $group ( split /\s*,\s*/, $tmpid ) { 
     829                my $optional = 0; 
     830 
     831                if ( $group =~ /^\(([^)]+)\)$/ ) { 
     832                    $optional = 1; 
     833                    $group    = $1; 
     834                } 
     835 
     836                my $g = &get_gid($group); 
     837                net_write( "DEBUG: Config: $service->gid = " 
     838                      . $sconf->{$service}{'group'} 
     839                      . "\n" ) 
     840                  if $DEBUG and defined $sconf->{$service}{'group'}; 
     841                if ( !defined $g and !$optional ) { 
     842                    warn 
     843"Group \"$group\" in configuration file \"$dir/$file\" nonexistant. Skipping plugin."; 
     844                    return undef; 
     845                } elsif ( !defined $g and $optional ) { 
     846                    net_write("DEBUG: Skipping \"$group\" (optional).\n") 
     847                      if $DEBUG; 
     848                    next; 
     849                } 
     850                if ( !defined $sconf->{$service}{'group'} ) { 
     851                    $sconf->{$service}{'group'} = $g; 
     852                } else { 
     853                    $sconf->{$service}{'group'} .= " $g"; 
     854                } 
     855            } ## end foreach my $group ( split /\s*,\s*/... 
     856        } ## end elsif (/^\s*group\s+(.+)\s*$/... 
     857        elsif (/^\s*command\s+(.+)\s*$/) { 
     858            @{ $sconf->{$service}{'command'} } = split( /\s+/, $1 ); 
     859        } elsif (/^\s*host_name\s+(.+)\s*$/) { 
     860            $sconf->{$service}{'host_name'} = $1; 
     861        } elsif (/^\s*timeout\s+(\d+)\s*$/) { 
     862            $sconf->{$service}{'timeout'} = $1; 
     863            net_write("DEBUG: $service: setting timeout to $1\n") 
     864              if $DEBUG; 
     865        } elsif ( /^\s*(allow)\s+(.+)\s*$/ or /^\s*(deny)\s+(.+)\s*$/ ) { 
     866            push( @{ $sconf->{$service}{'allow_deny'} }, [ $1, $2 ] ); 
     867            print STDERR "DEBUG: Pushing allow_deny: $1, $2\n" if $DEBUG; 
     868        } elsif (/^\s*env\s+([^=\s]+)\s*=\s*(.+)$/) { 
     869 
     870# $sconf->{$service}{'env'}{$1} = $2; 
     871# net_write ("Saving $service->env->$1 = $2...\n") if $DEBUG; 
     872            warn 
     873"Warning: Deprecated format in \"$dir/$file\" under \"[$service]\" (\"env $1=$2\" should be rewritten to \"env.$1 $2. Ignored.\")."; 
     874        } elsif (/^\s*env\.(\S+)\s+(.+)$/) { 
     875            $sconf->{$service}{'env'}{$1} = $2; 
     876            net_write("Saving $service->env->$1 = $2...\n") if $DEBUG; 
     877        } elsif (/^\s*(\w+)\s+(.+)$/) { 
     878 
     879# $sconf->{$service}{'env'}{"lrrd_$1"} = $2; 
     880# net_write ("Saving $service->env->lrrd_$1 = $2...\n") if $DEBUG; 
     881            warn 
     882"Warning: Deprecated format in \"$dir/$file\" under \"[$service]\" (\"$1 $2\" should be rewritten to \"env.$1 $2. Ignored.\")."; 
     883        } elsif (/\S/) { 
     884            warn 
     885"Warning: Unknown config option in \"$dir/$file\" under \"[$service]\": $_"; 
     886        } 
     887 
     888    } ## end while (<IN>) 
     889    close(IN); 
    956890 
    957891    return 1; 
    958 
    959  
    960 sub check_perms 
    961 
     892} ## end sub load_auth_file 
     893 
     894sub check_perms { 
    962895    my $target = shift; 
    963896    my @stat; 
    964     return undef if (!defined $target); 
    965         return 1 if (!$paranoia); 
    966  
    967     if (! -e "$target") 
     897    return undef if ( !defined $target ); 
     898    return 1     if ( !$paranoia ); 
     899 
     900    if ( !-e "$target" ) { 
     901        warn "Failed to check permissions on nonexistant target: \"$target\""; 
     902        return undef; 
     903    } 
     904 
     905    @stat = stat($target); 
     906    if (   !$stat[4] == 0 
     907        or ( $stat[5] != 0 and $stat[2] & 00020 ) 
     908        or ( $stat[2] & 00002 ) ) 
    968909    { 
    969         warn "Failed to check permissions on nonexistant target: \"$target\""; 
    970         return undef; 
    971     } 
    972  
    973     @stat = stat ($target); 
    974     if (!$stat[4] == 0 or 
    975         ($stat[5] != 0 and $stat[2] & 00020) or 
    976         ($stat[2] & 00002)) 
     910        warn "Warning: \"$target\" has dangerous permissions (", 
     911          sprintf( "%04o", $stat[2] & 07777 ), ")."; 
     912        return 0; 
     913    } 
     914 
     915    if ( -f "$target" )    # Check dir as well 
    977916    { 
    978         warn "Warning: \"$target\" has dangerous permissions (", sprintf ("%04o", $stat[2] & 07777), ")."; 
    979         return 0; 
    980     } 
    981  
    982     if (-f "$target") # Check dir as well 
    983     { 
    984         (my $dirname = $target) =~ s/[^\/]+$//; 
    985         return &check_perms ($dirname); 
     917        ( my $dirname = $target ) =~ s/[^\/]+$//; 
     918        return &check_perms($dirname); 
    986919    } 
    987920 
    988921    return 1; 
    989 
    990  
    991 sub get_var_arr 
    992 
    993     my $sconf   = shift; 
    994     my $name    = shift; 
    995     my $var     = shift; 
    996     my $result  = []; 
    997  
    998     if (exists $sconf->{$name}{$var}) 
    999     { 
    1000         push (@{$result}, $sconf->{$name}{$var}); 
    1001     } 
    1002  
    1003     foreach my $wildservice (grep (/\*$/, reverse sort keys %{$sconf})) 
    1004     { 
    1005         (my $tmpservice = $wildservice) =~ s/\*$//; 
    1006         next unless ($name =~ /^$tmpservice/); 
    1007         print STDERR "# Checking $wildservice...\n" if $DEBUG; 
    1008  
    1009         if (defined $sconf->{$wildservice}{$var}) 
    1010         { 
    1011             push (@{$result}, $sconf->{$wildservice}{$var}); 
    1012             print STDERR ("DEBUG: Pushing: |", join (';', @{$sconf->{$wildservice}{$var}}), "|\n") 
    1013                 if $DEBUG; 
    1014         } 
     922} ## end sub check_perms 
     923 
     924sub get_var_arr { 
     925    my $sconf  = shift; 
     926    my $name   = shift; 
     927    my $var    = shift; 
     928    my $result = []; 
     929 
     930    if ( exists $sconf->{$name}{$var} ) { 
     931        push( @{$result}, $sconf->{$name}{$var} ); 
     932    } 
     933 
     934    foreach my $wildservice ( grep ( /\*$/, reverse sort keys %{$sconf} ) ) { 
     935        ( my $tmpservice = $wildservice ) =~ s/\*$//; 
     936        next unless ( $name =~ /^$tmpservice/ ); 
     937        print STDERR "# Checking $wildservice...\n" if $DEBUG; 
     938 
     939        if ( defined $sconf->{$wildservice}{$var} ) { 
     940            push( @{$result}, $sconf->{$wildservice}{$var} ); 
     941            print STDERR ( 
     942                "DEBUG: Pushing: |", 
     943                join( ';', @{ $sconf->{$wildservice}{$var} } ), "|\n" 
     944            ) if $DEBUG; 
     945        } 
    1015946    } 
    1016947    return $result; 
    1017 
    1018  
    1019 sub get_var 
    1020 
    1021     my $sconf   = shift; 
    1022     my $name    = shift; 
    1023     my $var     = shift; 
    1024     my $env     = shift; 
    1025  
    1026     if (!defined $var and defined $name) 
    1027     { 
    1028         return $sconf{$name}; 
    1029     } 
    1030     if ($var eq 'env' and !defined $env) 
    1031     { 
    1032         %{$env} = (); 
    1033     } 
    1034      
    1035     if ($var ne 'env' and exists $sconf->{$name}{$var}) 
    1036     { 
    1037         return $sconf->{$name}{$var}; 
    1038     } 
    1039     # Deciding environment 
    1040     foreach my $wildservice (grep (/\*$/, reverse sort keys %{$sconf})) 
    1041     { 
    1042         (my $tmpservice = $wildservice) =~ s/\*$//; 
    1043         next unless ($name =~ /^$tmpservice/); 
     948} ## end sub get_var_arr 
     949 
     950sub get_var { 
     951    my $sconf = shift; 
     952    my $name  = shift; 
     953    my $var   = shift; 
     954    my $env   = shift; 
     955 
     956    if ( !defined $var and defined $name ) { 
     957        return $sconf{$name}; 
     958    } 
     959    if ( $var eq 'env' and !defined $env ) { 
     960        %{$env} = (); 
     961    } 
     962 
     963    if ( $var ne 'env' and exists $sconf->{$name}{$var} ) { 
     964        return $sconf->{$name}{$var}; 
     965    } 
     966 
     967# Deciding environment 
     968    foreach my $wildservice ( grep ( /\*$/, reverse sort keys %{$sconf} ) ) { 
     969        ( my $tmpservice = $wildservice ) =~ s/\*$//; 
     970        next unless ( $name =~ /^$tmpservice/ ); 
     971 
    1044972#       net_write ("# Checking $wildservice...\n") if $DEBUG; 
    1045973 
    1046         if ($var eq 'env') 
    1047         { 
    1048             if (exists $sconf->{$wildservice}{'env'}) 
    1049             { 
    1050                 foreach my $key (keys %{$sconf->{$wildservice}{'env'}}) 
    1051                 { 
    1052                     if (! exists $sconf->{$name}{'env'}{$key}) 
    1053                     { 
    1054                         $sconf->{$name}{'env'}{$key} = $sconf->{$wildservice}{'env'}{$key}; 
    1055                         net_write ("Saving $wildservice->$key\n") if $DEBUG; 
    1056                     } 
    1057                 } 
    1058             } 
    1059         } 
    1060         else 
    1061         { 
    1062             if (! exists $sconf->{$name}{$var} and 
    1063                     exists $sconf->{$wildservice}{$var}) 
    1064             { 
    1065                 return ($sconf->{$wildservice}{$var}); 
    1066             } 
    1067         } 
    1068     } 
     974        if ( $var eq 'env' ) { 
     975            if ( exists $sconf->{$wildservice}{'env'} ) { 
     976                foreach my $key ( keys %{ $sconf->{$wildservice}{'env'} } ) { 
     977                    if ( !exists $sconf->{$name}{'env'}{$key} ) { 
     978                        $sconf->{$name}{'env'}{$key} = 
     979                          $sconf->{$wildservice}{'env'}{$key}; 
     980                        net_write("Saving $wildservice->$key\n") if $DEBUG; 
     981                    } 
     982                } 
     983            } 
     984        } else { 
     985            if ( !exists $sconf->{$name}{$var} 
     986                and exists $sconf->{$wildservice}{$var} ) 
     987            { 
     988                return ( $sconf->{$wildservice}{$var} ); 
     989            } 
     990        } 
     991    } ## end foreach my $wildservice ( grep... 
    1069992    return $env; 
    1070 } 
     993} ## end sub get_var 
    1071994 
    10729951; 
     
    11521075=head1 COPYRIGHT 
    11531076 
    1154 Copyright © 2002-2006 Audun Ytterdal, Jimmy Olsen, and Tore Anderson / Linpro AS. 
     1077Copyright ᅵ 2002-2006 Audun Ytterdal, Jimmy Olsen, and Tore Anderson / Linpro AS. 
    11551078 
    11561079This is free software; see the source for copying conditions. There is 
     
    11621085=cut 
    11631086 
     1087 
    11641088# vim:syntax=perl ts=8 
  • people/janl/src/node/munin-run

    r1249 r1257  
    1 #!@@PERL@@ -wT 
    2 # -*- perl -*- 
     1#!/usr/bin/perl -wT 
    32 
    43# Copyright (C) 2004-2006 
     
    2221 
    2322use strict; 
     23use Munin; 
     24use Munin::Node; 
    2425use vars qw(@ISA); 
    2526use Getopt::Long; 
    2627 
    27 # "Clean" environment to disable taint-checking on the environment. We _know_ 
    28 # that the environment is insecure, but we want to let admins shoot themselves 
    29 # in the foot with it, if they want to. 
    30 foreach my $key (keys %ENV) 
    31 
    32         if ($ENV{$key} =~ /^(.*)$/) { 
    33             $ENV{$key} = $1; 
    34         } else { 
    35             delete $ENV{$key}; 
    36         } 
    37 
    38  
    39 $0 =~ /^(.*)$/; # for some strange reason won't "$0 = $0;" work. 
     28clean_envir; 
     29 
     30$0 =~ /^(.*)$/;    # for some strange reason won't "$0 = $0;" work. 
    4031$0 = $1; 
    41  
    42 # Make configuration settings available at runtime. 
    43 $ENV{'MUNIN_PREFIX'}     = '@@PREFIX@@'; 
    44 $ENV{'MUNIN_CONFDIR'}    = '@@CONFDIR@@';   # /etc/munin,/etc/opt/munin or such 
    45 $ENV{'MUNIN_BINDIR'}     = '@@BINDIR@@'; 
    46 $ENV{'MUNIN_SBINDIR'}    = '@@SBINDIR@@'; 
    47 $ENV{'MUNIN_DOCDIR'}     = '@@DOCDIR@@'; 
    48 $ENV{'MUNIN_LIBDIR'}     = '@@LIBDIR@@';    # LIBDIR/plugins contains plugin.sh 
    49 $ENV{'MUNIN_HTMLDIR'}    = '@@HTMLDIR@@'; 
    50 $ENV{'MUNIN_CGIDIR'}     = '@@CGIDIR@@'; 
    51 $ENV{'MUNIN_DBDIR'}      = '@@DBDIR@@'; 
    52 $ENV{'MUNIN_PLUGSTATE'}  = '@@PLUGSTATE@@'; # Put plugin state files here! 
    53 $ENV{'MUNIN_MANDIR'}     = '@@MANDIR@@'; 
    54 $ENV{'MUNIN_LOGDIR'}     = '@@LOGDIR@@'; 
    55 $ENV{'MUNIN_STATEDIR'}   = '@@STATEDIR@@';  # This is for .pid files 
    56 $ENV{'MUNIN_USER'}       = '@@USER@@';      # User munin runs as (mostly) 
    57 $ENV{'MUNIN_GROUP'}      = '@@GROUP@@';     # Group ditto 
    58 $ENV{'MUNIN_PLUGINUSER'} = '@@PLUGINUSER@@';# Default user for plugin running 
    59 $ENV{'MUNIN_VERSION'}    = '@@VERSION@@'; 
    60 $ENV{'MUNIN_PERL'}       = '@@PERL@@'; 
    61 $ENV{'MUNIN_PERLLIB'}    = '@@PERLLIB@@'; 
    62 $ENV{'MUNIN_GOODSH'}     = '@@GOODSH@@'; 
    63 $ENV{'MUNIN_BASH'}       = '@@BASH@@'; 
    64 $ENV{'MUNIN_PYTHON'}     = '@@PYTHON@@'; 
    65 $ENV{'MUNIN_OSTYPE'}     = '@@OSTYPE@@'; 
    66 $ENV{'MUNIN_HOSTNAME'}   = '@@HOSTNAME@@'; 
    67 $ENV{'MUNIN_MKTEMP'}     = '@@MKTEMP@@'; 
    6832 
    6933my %services; 
    7034my %nodes; 
    71 my $servicedir="@@CONFDIR@@/plugins"; 
    72 my $sconfdir="@@CONFDIR@@/plugin-conf.d"; 
    73 my $conffile="@@CONFDIR@@/munin-node.conf"; 
    74 my $sconffile=undef; 
    75 my $FQDN=""; 
    76 my $do_usage = 0; 
    77 my $DEBUG = 0; 
     35my $servicedir = "$CONFDIR/plugins"; 
     36my $sconfdir   = "$CONFDIR/plugin-conf.d"; 
     37my $conffile   = "$CONFDIR/munin-node.conf"; 
     38my $sconffile  = undef; 
     39my $FQDN       = ""; 
     40my $do_usage   = 0; 
     41my $DEBUG      = 0; 
    7842my $do_version = 0; 
    79 my $VERSION='@@VERSION@@'; 
    80 my $defuser = getpwnam ("@@PLUGINUSER@@"); 
    81 my $defgroup= getgrnam ("@@GROUP@@"); 
    82 my $paranoia = 0; 
    83 my @ignores = (); 
    84  
    85 my %sconf  = (); 
    86  
    87 $do_usage=1  unless 
    88 GetOptions ( "config=s"     => \$conffile, 
    89              "debug!"       => \$DEBUG, 
    90              "version!"     => \$do_version, 
    91              "servicedir=s" => \$servicedir, 
    92              "sconfdir=s"   => \$sconfdir, 
    93              "sconffile=s"  => \$sconffile, 
    94              "paranoia!"    => \$paranoia, 
    95              "help"         => \$do_usage ); 
    96  
    97 if ($do_usage) 
    98 
     43my $VERSION    = '@@VERSION@@'; 
     44my $defuser    = getpwnam($PLUGINUSER); 
     45my $defgroup   = getgrnam($GROUP); 
     46my $paranoia   = 0; 
     47my @ignores    = (); 
     48 
     49my %sconf = (); 
     50 
     51$do_usage = 1 
     52  unless GetOptions( 
     53    "config=s"     => \$conffile, 
     54    "debug!"       => \$DEBUG, 
     55    "version!"     => \$do_version, 
     56    "servicedir=s" => \$servicedir, 
     57    "sconfdir=s"   => \$sconfdir, 
     58    "sconffile=s"  => \$sconffile, 
     59    "paranoia!"    => \$paranoia, 
     60    "help"         => \$do_usage 
     61  ); 
     62 
     63if ($do_usage) { 
    9964    print "Usage: $0 [options] 
    10065 
     
    10267    --help              View this message. 
    10368    --config <file>     Use <file> as configuration file.  
    104                         [@@CONFDIR@@/munin-node.conf] 
     69                        [$CONFDIR/munin-node.conf] 
    10570    --servicedir <dir>  Dir where plugins are found.  
    106                         [@@CONFDIR@@/plugins] 
     71                        [$CONFDIR/plugins] 
    10772    --sconfdir <dir>    Dir where plugin configurations are found.  
    108                         [@@CONFDIR@@/plugin-conf.d] 
     73                        [$CONFDIR/plugin-conf.d] 
    10974    --sconffile <dir>   Dir where plugins are found. Overrides sconfdir. 
    11075                        [undefined] 
     
    11681"; 
    11782    exit 0; 
    118 
    119  
    120 if ($conffile =~ /^([-\/\@_\w\.]+)$/)  
    121 
    122     $conffile = $1;                     # $data now untainted 
    123 }  
    124 else  
    125 
    126     die "Bad data in $conffile";        # log this somewhere 
    127 
    128 if ($sconfdir =~ /^([-\/\@_\w\.]+)$/)  
    129 
    130     $sconfdir = $1;                     # $data now untainted 
    131 }  
    132 else  
    133 
    134     die "Bad data in $sconfdir";        # log this somewhere 
    135 
    136 if (defined $sconffile and $sconffile =~ /^([-\/\@_\w\.]+)$/)  
    137 
    138     $sconffile = $1;                     # $data now untainted 
    139 }  
    140 elsif (defined $sconffile)  
    141 
    142     die "Bad data in $sconffile";        # log this somewhere 
    143 
    144 if ($servicedir =~ /^([-\/\@_\w\.]+)$/)  
    145 
    146     $servicedir = $1;                     # $data now untainted 
    147 }  
    148 else  
    149 
    150     die "Bad data in $servicedir";        # log this somewhere 
    151 
    152  
    153  
    154  
    155 if ($do_version) 
    156 
    157         print <<"EOT"; 
    158 munin-run (munin-node) version $VERSION. 
    159 Written by Jimmy Olsen / Linpro AS 
    160  
    161 Copyright (C) 2002-2005 
    162  
    163 This is free software released under the GNU General Public License. There 
    164 is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR 
    165 PURPOSE. For details, please refer to the file COPYING that is included 
    166 with this software or refer to 
    167   http://www.fsf.org/licensing/licenses/gpl.txt 
    168 EOT 
    169         exit 0; 
     83} ## end if ($do_usage) 
     84 
     85if ( $conffile =~ /^([-\/\@_\w\.]+)$/ ) { 
     86    $conffile = $1;    # $data now untainted 
     87} else { 
     88    die "Bad data in $conffile";    # log this somewhere 
     89
     90 
     91if ( $sconfdir =~ /^([-\/\@_\w\.]+)$/ ) { 
     92    $sconfdir = $1;                 # $data now untainted 
     93} else { 
     94    die "Bad data in $sconfdir";    # log this somewhere 
     95
     96 
     97if ( defined $sconffile and $sconffile =~ /^([-\/\@_\w\.]+)$/ ) { 
     98    $sconffile = $1;                # $data now untainted 
     99} elsif ( defined $sconffile ) { 
     100    die "Bad data in $sconffile";    # log this somewhere 
     101
     102 
     103if ( $servicedir =~ /^([-\/\@_\w\.]+)$/ ) { 
     104    $servicedir = $1;                # $data now untainted 
     105} else { 
     106    die "Bad data in $servicedir";    # log this somewhere 
     107
     108 
     109if ($do_version) { 
     110    print "munin-run (munin-node) version $VERSION.". 
     111        Munin::copyright; 
     112    exit 0; 
    170113} 
    171114 
    172115# Check permissions of configuration 
    173116 
    174 if (!&check_perms ($servicedir) or !&check_perms ($conffile)) 
    175 
    176         die "Fatal error. Bailing out."; 
    177 
    178  
    179 if (! -f $conffile) { 
    180   print "ERROR: Cannot open $conffile\n"; 
    181   exit 1; 
    182 
    183  
    184 open FILE,$conffile or die "Cannot open $conffile\n"; 
     117if ( !&check_perms($servicedir) or !&check_perms($conffile) ) { 
     118    die "Fatal error. Bailing out."; 
     119
     120 
     121if ( !-f $conffile ) { 
     122    print "ERROR: Cannot open $conffile\n"; 
     123    exit 1; 
     124
     125 
     126open FILE, $conffile or die "Cannot open $conffile\n"; 
    185127while (<FILE>) { 
    186   chomp; 
    187   s/#.*//;                # no comments 
    188   s/^\s+//;               # no leading white 
    189   s/\s+$//;               # no trailing white 
    190   next unless length;     # anything left? 
    191   /(^\w*)\s+(.*)/; 
    192   if (($1 eq "host_name" or $1 eq "hostname") and $2) 
    193   { 
    194       $FQDN=$2; 
    195   } 
    196   elsif (($1 eq "default_plugin_user" or $1 eq "default_client_user") and $2) 
    197   { 
    198       my $tmpid = $2; 
    199       my $defuser = &get_uid ($tmpid); 
    200       if (! defined ($defuser)) 
    201       { 
    202           die "Default user defined in \"$conffile\" does not exist ($tmpid)"; 
    203       } 
    204   } 
    205   elsif (($1 eq "default_plugin_group" or $1 eq "default_client_group") and $2) 
    206   { 
    207       my $tmpid = $2; 
    208       $defgroup = &get_gid ($tmpid); 
    209       if (! defined ($defgroup)) 
    210       { 
    211           die "Default group defined in \"$conffile\" does not exist ($tmpid)"; 
    212       } 
    213   } 
    214   elsif (($1 eq "paranoia") and defined $2) 
    215   { 
    216       if ("$2" eq "no" or "$2" eq "false" or "$2" eq "off" or "$2" eq "0") 
    217       { 
    218           $paranoia = 0; 
    219       }    
    220       else 
    221       { 
    222           $paranoia = 1; 
    223       }    
    224   }    
    225   elsif (($1 eq "ignore_file") and defined $2) 
    226   { 
    227           push @ignores, $2; 
    228   }    
    229 
     128    chomp; 
     129    s/#.*//;     # no comments 
     130    s/^\s+//;    # no leading white 
     131    s/\s+$//;    # no trailing white 
     132    next unless length;    # anything left? 
     133    /(^\w*)\s+(.*)/; 
     134    if ( ( $1 eq "host_name" or $1 eq "hostname" ) and $2 ) { 
     135        $FQDN = $2; 
     136    } elsif ( ( $1 eq "default_plugin_user" or $1 eq "default_client_user" ) 
     137        and $2 ) 
     138    { 
     139        my $tmpid   = $2; 
     140        my $defuser = &get_uid($tmpid); 
     141        if ( !defined($defuser) ) { 
     142            die 
     143              "Default user defined in \"$conffile\" does not exist ($tmpid)"; 
     144        } 
     145    } elsif ( ( $1 eq "default_plugin_group" or $1 eq "default_client_group" ) 
     146        and $2 ) { 
     147        my $tmpid = $2; 
     148        $defgroup = &get_gid($tmpid); 
     149        if ( !defined($defgroup) ) { 
     150            die "Default group defined in '$conffile' does not exist ($tmpid)"; 
     151        } 
     152    } elsif ( ( $1 eq "paranoia" ) and defined $2 ) { 
     153        if ( "$2" eq "no" or "$2" eq "false" or "$2" eq "off" or "$2" eq "0" ) 
     154        { 
     155            $paranoia = 0; 
     156        } else { 
     157            $paranoia = 1; 
     158        } 
     159    } elsif ( ( $1 eq "ignore_file" ) and defined $2 ) { 
     160        push @ignores, $2; 
     161    } 
     162} ## end while (<FILE>) 
    230163 
    231164$FQDN ||= &get_fq_hostname; 
    232165 
    233 $ENV{'FQDN'}=$FQDN; 
    234  
    235 # Some locales uses "," as decimal separator. This can mess up a lot 
    236 # of plugins. 
    237 $ENV{'LC_ALL'}='C'; 
     166$ENV{'FQDN'} = $FQDN; 
    238167 
    239168&load_services; 
     
    244173 
    245174sub load_services { 
    246     if ($sconffile) 
    247     { 
    248         if (!&load_auth_file ("", $sconffile, \%sconf)) 
    249         { 
    250             warn "Something wicked happened while reading \"$sconffile\". Check the previous log lines for spesifics."; 
    251         } 
    252     } 
    253     else 
    254     { 
    255         if (opendir (DIR,$sconfdir)) 
    256         { 
    257 FILES: 
    258             for my $file (grep { -f "$sconfdir/$_" } readdir (DIR)) 
    259             { 
    260                 next if $file =~ m/^\./; # Hidden files 
    261                 next if $file !~ m/^([-\w.]+)$/; # Skip if any weird chars 
    262                 $file = $1; # Not tainted anymore. 
    263                 foreach my $regex (@ignores) 
    264                 { 
    265                         next FILES if $file =~ /$regex/; 
    266                 } 
    267                 if (!&load_auth_file ($sconfdir, $file, \%sconf)) 
    268                 { 
    269                     warn "Something wicked happened while reading \"$servicedir/$file\". Check the previous log lines for spesifics."; 
    270                 } 
    271             } 
    272             closedir (DIR); 
    273         } 
    274     } 
    275      
    276     opendir (DIR,$servicedir) || die "Cannot open plugindir: $servicedir $!"; 
    277 FILES: 
    278     for my $file (grep { -f "$servicedir/$_" } readdir(DIR)) { 
    279         next if $file =~ m/^\./; # Hidden files 
    280         next if $file =~ m/.conf$/; # Config files 
    281         next if $file !~ m/^([-\w.]+)$/; # Skip if any weird chars 
    282         $file = $1; # Not tainted anymore. 
    283         foreach my $regex (@ignores) 
    284         { 
    285                 next FILES if $file =~ /$regex/; 
    286         } 
    287         next if (! -x "$servicedir/$file"); # File not executeable 
    288         next unless ($file =~ /^$ARGV[0]$/); 
    289         print "# file: '$file'\n" if $DEBUG; 
    290         my $arg = undef; 
    291         if (defined $ARGV[1]) 
    292         { 
    293             if ($ARGV[1] =~ /^c/i) 
    294             { 
    295                 $arg = "config"; 
    296             } 
    297             elsif ($ARGV[1] =~ /^a/i) 
    298             { 
    299                 $arg = "autoconf"; 
    300             } 
    301             elsif ($ARGV[1] =~ /^snmp/i) 
    302             { 
    303                 $arg = "snmpconf"; 
    304             } 
    305             elsif ($ARGV[1] =~ /^s/i) 
    306             { 
    307                 $arg = "suggest"; 
    308             } 
    309         } 
    310         $services{$file}=1; 
    311         my @rows = run_service($file, $arg); 
    312         my $node = $FQDN; 
    313         for my $row (@rows) { 
    314           print "# row: $row\n" if $DEBUG; 
    315           if ($row =~ m/^host_name (.+)$/) { 
    316             print "# Found host_name, using it\n" if $DEBUG; 
    317             $node = $1; 
    318           } 
    319         } 
    320         $nodes{$node}{$file}=1; 
    321     } 
     175    if ($sconffile) { 
     176        if ( !&load_auth_file( "", $sconffile, \%sconf ) ) { 
     177            warn 
     178"Something wicked happened while reading \"$sconffile\". Check the previous log lines for spesifics."; 
     179        } 
     180    } else { 
     181        if ( opendir( DIR, $sconfdir ) ) { 
     182          FILES: 
     183            for my $file ( grep { -f "$sconfdir/$_" } readdir(DIR) ) { 
     184                next if $file =~ m/^\./;    # Hidden files 
     185                next if $file !~ m/^([-\w.]+)$/;    # Skip if any weird chars 
     186                $file = $1;                         # Not tainted anymore. 
     187                foreach my $regex (@ignores) { 
     188                    next FILES if $file =~ /$regex/; 
     189                } 
     190                if ( !&load_auth_file( $sconfdir, $file, \%sconf ) ) { 
     191                    warn 
     192"Something wicked happened while reading \"$servicedir/$file\". Check the previous log lines for spesifics."; 
     193                } 
     194            } 
     195            closedir(DIR); 
     196        } ## end if ( opendir( DIR, $sconfdir... 
     197    } ## end else[ if ($sconffile) 
     198 
     199    opendir( DIR, $servicedir ) 
     200      || die "Cannot open plugindir: $servicedir $!"; 
     201  FILES: 
     202    for my $file ( grep { -f "$servicedir/$_" } readdir(DIR) ) { 
     203        next if $file =~ m/^\./;       # Hidden files 
     204        next if $file =~ m/.conf$/;    # Config files 
     205        next if $file !~ m/^([-\w.]+)$/;    # Skip if any weird chars 
     206        $file = $1;                         # Not tainted anymore. 
     207        foreach my $regex (@ignores) { 
     208            next FILES if $file =~ /$regex/; 
     209        } 
     210        next if ( !-x "$servicedir/$file" );    # File not executeable 
     211        next unless ( $file =~ /^$ARGV[0]$/ ); 
     212        print "# file: '$file'\n" if $DEBUG; 
     213        my $arg = undef; 
     214        if ( defined $ARGV[1] ) { 
     215            if ( $ARGV[1] =~ /^c/i ) { 
     216                $arg = "config"; 
     217            } elsif ( $ARGV[1] =~ /^a/i ) { 
     218                $arg = "autoconf"; 
     219            } elsif ( $ARGV[1] =~ /^snmp/i ) { 
     220                $arg = "snmpconf"; 
     221            } elsif ( $ARGV[1] =~ /^s/i ) { 
     222                $arg = "suggest"; 
     223            } 
     224        } 
     225        $services{$file} = 1; 
     226        my @rows = run_service( $file, $arg ); 
     227        my $node = $FQDN; 
     228        for my $row (@rows) { 
     229            print "# row: $row\n" if $DEBUG; 
     230            if ( $row =~ m/^host_name (.+)$/ ) { 
     231                print "# Found host_name, using it\n" if $DEBUG; 
     232                $node = $1; 
     233            } 
     234        } 
     235        $nodes{$node}{$file} = 1; 
     236    } ## end for my $file ( grep { -f... 
    322237    closedir DIR; 
    323238    print "ERROR: Could not execute plugin (plugin doesn't exist?).\n"; 
    324239    exit 1; 
    325 } 
     240} ## end sub load_services 
    326241 
    327242sub run_service { 
    328   my ($service,$command) = @_; 
    329   $command ||=""; 
    330   my @lines = ();; 
    331   my $timed_out = 0; 
    332   if ($services{$service}) { 
    333     my $child = 0; 
    334     local $SIG{ALRM} = sub {  
    335       $timed_out = 1;  
    336     }; 
    337  
    338     # Setting environment 
    339     $sconf{$service}{user}    = &get_var (\%sconf, $service, 'user'); 
    340     $sconf{$service}{group}   = &get_var (\%sconf, $service, 'group'); 
    341     $sconf{$service}{command} = &get_var (\%sconf, $service, 'command'); 
    342     &get_var (\%sconf, $service, 'env', \%{$sconf{$service}{env}}); 
    343      
    344         if ($< == 0) # If root 
    345         { 
    346                 # Giving up gid egid uid euid 
    347                 my $u  = (defined $sconf{$service}{'user'}? 
    348                         $sconf{$service}{'user'}: 
    349                         $defuser); 
    350                 my $g  = $defgroup; 
    351                 my $gs = "$g $g" . 
    352                   (defined($sconf{$service}{'group'}) ?  
    353                    " $sconf{$service}{group}" : ""); 
    354  
    355                 print "# Want to run as euid/egid $u/$g\n" if $DEBUG; 
    356  
    357                 $( = $g    unless $g == 0; 
    358                 $) = $gs   unless $g == 0; 
    359                 $< = $u    unless $u == 0; 
    360                 $> = $u    unless $u == 0; 
    361  
    362                 if ($> != $u or $g != (split (' ', $)))[0]) 
    363                 { 
    364                 print "# Can't drop privileges. Bailing out. (wanted uid=",  
    365                 ($sconf{$service}{'user'} || $defuser), " gid=\"",  
    366                 $gs, "\"($g), got uid=$> gid=\"$)\"(", (split (' ', $)))[0], ").\n"; 
    367                 exit 1; 
    368                 } 
    369                 print "# Running as uid/gid/euid/egid $</$(/$>/$)\n" if $DEBUG; 
    370                 if (!&check_perms ("$servicedir/$service")) 
    371                 { 
    372                 print "# Error: unsafe permissions. Bailing out."; 
    373                 exit 1; 
    374                 } 
    375         } 
    376  
    377     # Setting environment... 
    378     if (exists $sconf{$service}{'env'} and 
    379             defined $sconf{$service}{'env'}) 
    380     { 
    381         foreach my $key (keys %{$sconf{$service}{'env'}}) 
    382         { 
    383             print "# Setting environment $key=$sconf{$service}{env}{$key}\n" 
    384               if $DEBUG; 
    385             $ENV{$key} = $sconf{$service}{env}{$key}; 
    386         } 
    387     } 
    388     if (exists $sconf{$service}{'command'} and 
    389         defined $sconf{$service}{'command'}) 
    390     { 
    391         my @run = (); 
    392         foreach my $t (@{$sconf{$service}{'command'}}) 
    393         { 
    394             if ($t =~ /^%c$/) 
    395             { 
    396                 push (@run, "$servicedir/$service", $command); 
    397             } 
    398             else 
    399             { 
    400                 push (@run, $t); 
    401             } 
    402         } 
    403         print "# About to run \"", join (' ', @run), "\"\n" if $DEBUG; 
    404         exec (@run) if @run; 
    405     } 
    406     else 
    407     { 
    408         print "# DEBUG: About to exec \"$servicedir/$service\"\n" 
    409           if $DEBUG; 
    410  
    411         if (!exec ("$servicedir/$service", $command)) 
    412         { 
    413             print "no (could not execute plugin)\n"; exit 1; 
    414         } 
    415     } 
    416   } else { 
    417     print "# Unknown service\n"; 
    418   } 
    419   chomp @lines; 
    420   return (@lines); 
    421 
     243    my ( $service, $command ) = @_; 
     244    $command ||= ""; 
     245    my @lines     = (); 
     246    my $timed_out = 0; 
     247    if ( $services{$service} ) { 
     248        my $child = 0; 
     249        local $SIG{ALRM} = sub { 
     250            $timed_out = 1; 
     251        }; 
     252 
     253# Setting environment 
     254        $sconf{$service}{user}    = &get_var( \%sconf, $service, 'user' ); 
     255        $sconf{$service}{group}   = &get_var( \%sconf, $service, 'group' ); 
     256        $sconf{$service}{command} = &get_var( \%sconf, $service, 'command' ); 
     257        &get_var( \%sconf, $service, 'env', \%{ $sconf{$service}{env} } ); 
     258 
     259        if ( $< == 0 )    # If root 
     260        { 
     261 
     262# Giving up gid egid uid euid 
     263            my $u = ( 
     264                defined $sconf{$service}{'user'} 
     265                ? $sconf{$service}{'user'} 
     266                : $defuser 
     267            ); 
     268            my $g  = $defgroup; 
     269            my $gs = "$g $g" 
     270              . ( 
     271                defined( $sconf{$service}{'group'} ) 
     272                ? " $sconf{$service}{group}" 
     273                : "" 
     274              ); 
     275 
     276            print "# Want to run as euid/egid $u/$g\n" if $DEBUG; 
     277 
     278            $( = $g  unless $g == 0; 
     279            $) = $gs unless $g == 0; 
     280            $< = $u  unless $u == 0; 
     281            $> = $u  unless $u == 0; 
     282 
     283            if ( $> != $u or $g != ( split( ' ', $) ) )[0] ) { 
     284                print "# Can't drop privileges. Bailing out. (wanted uid=", 
     285                  ( $sconf{$service}{'user'} || $defuser ), " gid=\"", $gs, 
     286                  "\"($g), got uid=$> gid=\"$)\"(", ( split( ' ', $) ) )[0], 
     287                  ").\n"; 
     288                exit 1; 
     289            } 
     290            print "# Running as uid/gid/euid/egid $</$(/$>/$)\n" if $DEBUG; 
     291            if ( !&check_perms("$servicedir/$service") ) { 
     292                print "# Error: unsafe permissions. Bailing out."; 
     293                exit 1; 
     294            } 
     295        } ## end if ( $< == 0 ) 
     296 
     297# Setting environment... 
     298        if ( exists $sconf{$service}{'env'} 
     299            and defined $sconf{$service}{'env'} ) 
     300        { 
     301            foreach my $key ( keys %{ $sconf{$service}{'env'} } ) { 
     302                print 
     303                  "# Setting environment $key=$sconf{$service}{env}{$key}\n" 
     304                  if $DEBUG; 
     305                $ENV{$key} = $sconf{$service}{env}{$key}; 
     306            } 
     307        } 
     308        if ( exists $sconf{$service}{'command'} 
     309            and defined $sconf{$service}{'command'} ) 
     310        { 
     311            my @run = (); 
     312            foreach my $t ( @{ $sconf{$service}{'command'} } ) { 
     313                if ( $t =~ /^%c$/ ) { 
     314                    push( @run, "$servicedir/$service", $command ); 
     315                } else { 
     316                    push( @run, $t ); 
     317                } 
     318            } 
     319            print "# About to run \"", join( ' ', @run ), "\"\n" if $DEBUG; 
     320            exec(@run) if @run; 
     321        } else { 
     322            print "# DEBUG: About to exec \"$servicedir/$service\"\n" 
     323              if $DEBUG; 
     324 
     325            if ( !exec( "$servicedir/$service", $command ) ) { 
     326                print "no (could not execute plugin)\n"; 
     327                exit 1; 
     328            } 
     329        } 
     330    } else { 
     331        print "# Unknown service\n"; 
     332    } 
     333    chomp @lines; 
     334    return (@lines); 
     335} ## end sub run_service 
    422336 
    423337sub get_fq_hostname { 
     
    425339    eval { 
    426340        require Sys::Hostname; 
    427         $hostname = (gethostbyname(Sys::Hostname::hostname()))[0]; 
     341        $hostname = ( gethostbyname( Sys::Hostname::hostname() ) )[0]; 
    428342    }; 
    429343    return $hostname if $hostname; 
    430344 
    431     $hostname = `hostname`;  # Fall$ 
     345    $hostname = `hostname`;    # Fall$ 
    432346    chomp($hostname); 
    433347    $hostname =~ s/\s//g; 
     
    435349} 
    436350 
    437  
    438 sub get_uid 
    439 
     351sub get_uid { 
    440352    my $user = shift; 
    441     return undef if (!defined $user); 
    442  
    443     if ($user !~ /\d/) 
    444     { 
    445         $user = getpwnam ($user); 
     353    return undef if ( !defined $user ); 
     354 
     355    if ( $user !~ /\d/ ) { 
     356        $user = getpwnam($user); 
    446357    } 
    447358    return $user; 
    448359} 
    449360 
    450 sub get_gid 
    451 
     361sub get_gid { 
    452362    my $group = shift; 
    453     return undef if (!defined $group); 
    454  
    455     if ($group !~ /\d/) 
    456     { 
    457         $group = getgrnam ($group); 
     363    return undef if ( !defined $group ); 
     364 
     365    if ( $group !~ /\d/ ) { 
     366        $group = getgrnam($group); 
    458367    } 
    459368    return $group; 
    460369} 
    461370 
    462 sub load_auth_file  
    463 
    464     my ($dir, $file, $sconf) = @_; 
     371sub load_auth_file { 
     372    my ( $dir, $file, $sconf ) = @_; 
    465373    my $service = $file; 
    466374 
    467     if (!defined $dir or !defined $file or !defined $sconf) 
    468     { 
    469         return undef; 
    470     } 
    471  
    472     return undef if (length $dir and !&check_perms ($dir)); 
    473     return undef if (!&check_perms ("$dir/$file")); 
    474  
    475     if (!open (IN, "$dir/$file")) 
    476     { 
    477         warn "Could not open file \"$dir/$file\" for reading ($!), skipping plugin\n"; 
    478         return undef; 
    479     } 
    480     while (<IN>) 
    481     { 
    482         chomp; 
    483         s/#.*$//; 
    484         next unless /\S/; 
    485         if (/^\s*\[([^\]]+)\]\s*$/) 
    486         { 
    487             $service = $1; 
    488         } 
    489         elsif (/^\s*user\s+(\S+)\s*$/) 
    490         { 
    491             my $tmpid = $1; 
    492             $sconf->{$service}{'user'} = &get_uid ($tmpid); 
    493             if (!defined $sconf->{$service}{'user'}) 
    494             { 
    495                 warn "User \"$tmpid\" in configuration file \"$dir/$file\" nonexistant. Skipping plugin."; 
    496                 return undef; 
    497             } 
    498         } 
    499         elsif (/^\s*group\s+(.+)\s*$/) 
    500         { 
    501             my $tmpid = $1; 
    502             foreach my $group (split /\s*,\s*/, $tmpid) 
    503             { 
    504                 my $optional = 0; 
    505  
    506                 if ($group =~ /^\(([^)]+)\)$/) 
    507                 { 
    508                     $optional = 1; 
    509                     $group = $1; 
    510                 } 
    511  
    512                 my $g = &get_gid ($group); 
    513                 if (!defined $g and !$optional) 
    514                 { 
    515                     warn "Group \"$group\" in configuration file \"$dir/$file\" nonexistant. Skipping plugin."; 
    516                     return undef; 
    517                 } 
    518                 elsif (!defined $g and $optional) 
    519                 { 
    520                     print "# DEBUG: Skipping \"$group\" (optional).\n" 
    521                       if $DEBUG; 
    522                     next; 
    523                 } 
    524                  
    525                 if (!defined $sconf->{$service}{'group'}) 
    526                 { 
    527                     $sconf->{$service}{'group'} = $g; 
    528                 } 
    529                 else 
    530                 { 
    531                     $sconf->{$service}{'group'} .= " $g"; 
    532                 } 
    533             } 
    534         } 
    535         elsif (/^\s*command\s+(.+)\s*$/) 
    536         { 
    537             @{$sconf->{$service}{'command'}} = split (/\s+/, $1); 
    538         } 
    539         elsif (/^\s*host_name\s+(.+)\s*$/) 
    540         { 
     375    if ( !defined $dir or !defined $file or !defined $sconf ) { 
     376        return undef; 
     377    } 
     378 
     379    return undef if ( length $dir and !&check_perms($dir) ); 
     380    return undef if ( !&check_perms("$dir/$file") ); 
     381 
     382    if ( !open( IN, "$dir/$file" ) ) { 
     383        warn 
     384"Could not open file \"$dir/$file\" for reading ($!), skipping plugin\n"; 
     385        return undef; 
     386    } 
     387    while (<IN>) { 
     388        chomp; 
     389        s/#.*$//; 
     390        next unless /\S/; 
     391        if (/^\s*\[([^\]]+)\]\s*$/) { 
     392            $service = $1; 
     393        } elsif (/^\s*user\s+(\S+)\s*$/) { 
     394            my $tmpid = $1; 
     395            $sconf->{$service}{'user'} = &get_uid($tmpid); 
     396            if ( !defined $sconf->{$service}{'user'} ) { 
     397                warn 
     398"User \"$tmpid\" in configuration file \"$dir/$file\" nonexistant. Skipping plugin."; 
     399                return undef; 
     400            } 
     401        } elsif (/^\s*group\s+(.+)\s*$/) { 
     402            my $tmpid = $1; 
     403            foreach my $group ( split /\s*,\s*/, $tmpid ) { 
     404                my $optional = 0; 
     405 
     406                if ( $group =~ /^\(([^)]+)\)$/ ) { 
     407                    $optional = 1; 
     408                    $group    = $1; 
     409                } 
     410 
     411                my $g = &get_gid($group); 
     412                if ( !defined $g and !$optional ) { 
     413                    warn 
     414"Group \"$group\" in configuration file \"$dir/$file\" nonexistant. Skipping plugin."; 
     415                    return undef; 
     416                } elsif ( !defined $g and $optional ) { 
     417                    print "# DEBUG: Skipping \"$group\" (optional).\n" 
     418                      if $DEBUG; 
     419                    next; 
     420                } 
     421 
     422                if ( !defined $sconf->{$service}{'group'} ) { 
     423                    $sconf->{$service}{'group'} = $g; 
     424                } else { 
     425                    $sconf->{$service}{'group'} .= " $g"; 
     426                } 
     427            } ## end foreach my $group ( split /\s*,\s*/... 
     428        } ## end elsif (/^\s*group\s+(.+)\s*$/... 
     429        elsif (/^\s*command\s+(.+)\s*$/) { 
     430            @{ $sconf->{$service}{'command'} } = split( /\s+/, $1 ); 
     431        } elsif (/^\s*host_name\s+(.+)\s*$/) { 
    541432            $sconf->{$service}{'host_name'} = $1; 
    542         }  
    543         elsif (/^\s*timeout\s+(\d+)\s*$/) 
    544         { 
     433        } elsif (/^\s*timeout\s+(\d+)\s*$/) { 
    545434            $sconf->{$service}{'timeout'} = $1; 
    546435            print "# DEBUG: $service: setting timeout to $1\n" 
    547                 if $DEBUG; 
    548         } 
    549         elsif (/^\s*(allow)\s+(.+)\s*$/ or /^\s*(deny)\s+(.+)\s*$/) 
    550         { 
    551             push (@{$sconf->{$service}{'allow_deny'}}, [$1, $2]); 
    552                 print "# DEBUG: Pushing allow_deny: $1, $2\n" if $DEBUG; 
    553         } 
    554         elsif (/^\s*env\s+([^=\s]+)\s*=\s*(.+)$/) 
    555         { 
     436              if $DEBUG; 
     437        } elsif ( /^\s*(allow)\s+(.+)\s*$/ or /^\s*(deny)\s+(.+)\s*$/ ) { 
     438            push( @{ $sconf->{$service}{'allow_deny'} }, [ $1, $2 ] ); 
     439            print "# DEBUG: Pushing allow_deny: $1, $2\n" if $DEBUG; 
     440        } elsif (/^\s*env\s+([^=\s]+)\s*=\s*(.+)$/) { 
    556441            $sconf->{$service}{'env'}{$1} = $2; 
    557442            print "# Saving $service->env->$1 = $2...\n" if $DEBUG; 
    558                         warn "Warning: Deprecated format in \"$dir/$file\" under \"[$service]\" (\"env $1=$2\" should be rewritten to \"env.$1 $2\")."; 
    559         }  
    560         elsif (/^\s*env\.(\S+)\s+(.+)$/) 
    561         { 
     443            warn 
     444"Warning: Deprecated format in \"$dir/$file\" under \"[$service]\" (\"env $1=$2\" should be rewritten to \"env.$1 $2\")."; 
     445        } elsif (/^\s*env\.(\S+)\s+(.+)$/) { 
    562446            $sconf->{$service}{'env'}{$1} = $2; 
    563447            print "# Saving $service->env->$1 = $2...\n" if $DEBUG; 
    564         } 
    565         elsif (/^\s*(\w+)\s+(.+)$/) 
    566         { 
     448        } elsif (/^\s*(\w+)\s+(.+)$/) { 
    567449            $sconf->{$service}{'env'}{"lrrd_$1"} = $2; 
    568450            print "# Saving $service->env->lrrd_$1 = $2...\n" if $DEBUG; 
    569             warn "Warning: Deprecated format in \"$dir/$file\" under \"[$service]\" (\"$1 $2\" should be rewritten to \"env.$1 $2\")."; 
    570         }  
    571         elsif (/\S/) 
    572         { 
    573             warn "Warning: Unknown config option in \"$dir/$file\" under \"[$service]\": $_"; 
    574         } 
    575     } 
    576     close (IN); 
     451            warn 
     452"Warning: Deprecated format in \"$dir/$file\" under \"[$service]\" (\"$1 $2\" should be rewritten to \"env.$1 $2\")."; 
     453        } elsif (/\S/) { 
     454            warn 
     455"Warning: Unknown config option in \"$dir/$file\" under \"[$service]\": $_"; 
     456        } 
     457    } ## end while (<IN>) 
     458    close(IN); 
    577459 
    578460    return 1; 
    579 
    580  
    581 sub check_perms 
    582 
     461} ## end sub load_auth_file 
     462 
     463sub check_perms { 
    583464    my $target = shift; 
    584465    my @stat; 
    585     return undef if (!defined $target); 
    586     return 1 if (!$paranoia); 
    587  
    588     if (! -e "$target") 
     466    return undef if ( !defined $target ); 
     467    return 1     if ( !$paranoia ); 
     468 
     469    if ( !-e "$target" ) { 
     470        warn "Failed to check permissions on nonexistant target: \"$target\""; 
     471        return undef; 
     472    } 
     473 
     474    @stat = stat($target); 
     475    if (   !$stat[4] == 0 
     476        or ( $stat[5] != 0 and $stat[2] & 00020 ) 
     477        or ( $stat[2] & 00002 ) ) 
    589478    { 
    590         warn "Failed to check permissions on nonexistant target: \"$target\""; 
    591         return undef; 
    592     } 
    593  
    594     @stat = stat ($target); 
    595     if (!$stat[4] == 0 or 
    596         ($stat[5] != 0 and $stat[2] & 00020) or 
    597         ($stat[2] & 00002)) 
     479        warn "Warning: \"$target\" has dangerous permissions (", 
     480          sprintf( "%04o", $stat[2] & 07777 ), ")."; 
     481        return 0; 
     482    } 
     483 
     484    if ( -f "$target" )    # Check dir as well 
    598485    { 
    599         warn "Warning: \"$target\" has dangerous permissions (", sprintf ("%04o", $stat[2] & 07777), ")."; 
    600         return 0; 
    601     } 
    602  
    603     if (-f "$target") # Check dir as well 
    604     { 
    605         (my $dirname = $target) =~ s/[^\/]+$//; 
    606         return &check_perms ($dirname); 
     486        ( my $dirname = $target ) =~ s/[^\/]+$//; 
     487        return &check_perms($dirname); 
    607488    } 
    608489 
    609490    return 1; 
    610 
    611  
    612 sub get_var 
    613 
    614     my $sconf   = shift; 
    615     my $name    = shift; 
    616     my $var     = shift; 
    617     my $env     = shift; 
    618  
    619     if ($var eq 'env' and !defined $env) 
    620     { 
     491} ## end sub check_perms 
     492 
     493sub get_var { 
     494    my $sconf = shift; 
     495    my $name  = shift; 
     496    my $var   = shift; 
     497    my $env   = shift; 
     498 
     499    if ( $var eq 'env' and !defined $env ) { 
    621500        %{$env} = (); 
    622501    } 
    623      
    624     if ($var ne 'env' and exists $sconf->{$name}{$var}) 
    625     { 
     502 
     503    if ( $var ne 'env' and exists $sconf->{$name}{$var} ) { 
    626504        return $sconf->{$name}{$var}; 
    627505    } 
    628     # Deciding environment 
    629     foreach my $wildservice (grep (/\*$/, reverse sort keys %{$sconf})) 
    630    
    631         (my $tmpservice = $wildservice) =~ s/\*$//; 
    632         next unless ($name =~ /^$tmpservice/); 
     506 
     507# Deciding environment 
     508    foreach my $wildservice ( grep ( /\*$/, reverse sort keys %{$sconf} ) )
     509        ( my $tmpservice = $wildservice ) =~ s/\*$//; 
     510        next unless ( $name =~ /^$tmpservice/ ); 
    633511        print "# Checking $wildservice...\n" if $DEBUG; 
    634512 
    635         if ($var eq 'env') 
    636         { 
    637             if (exists $sconf->{$wildservice}{'env'}) 
    638             { 
    639                 foreach my $key (keys %{$sconf->{$wildservice}{'env'}}) 
    640                 { 
    641                     if (! exists $sconf->{$name}{'env'}{$key}) 
    642                     { 
    643                         $sconf->{$name}{'env'}{$key} = $sconf->{$wildservice}{'env'}{$key}; 
     513        if ( $var eq 'env' ) { 
     514            if ( exists $sconf->{$wildservice}{'env'} ) { 
     515                foreach my $key ( keys %{ $sconf->{$wildservice}{'env'} } ) { 
     516                    if ( !exists $sconf->{$name}{'env'}{$key} ) { 
     517                        $sconf->{$name}{'env'}{$key} = 
     518                          $sconf->{$wildservice}{'env'}{$key}; 
    644519                        print "# Saving $wildservice->$key\n" if $DEBUG; 
    645520                    } 
    646521                } 
    647522            } 
    648         } 
    649         else 
    650         { 
    651             if (! exists $sconf->{$name}{$var} and 
    652                     exists $sconf->{$wildservice}{$var}) 
     523        } else { 
     524            if ( !exists $sconf->{$name}{$var} 
     525                and exists $sconf->{$wildservice}{$var} ) 
    653526            { 
    654                 return ($sconf->{$wildservice}{$var}); 
    655             } 
    656         } 
    657     } 
     527                return ( $sconf->{$wildservice}{$var} ); 
     528            } 
     529        } 
     530    } ## end foreach my $wildservice ( grep... 
    658531    return $env; 
    659 
    660  
    661  
     532} ## end sub get_var 
    662533 
    6635341; 
     
    746617 
    747618Copyright (C) 2002-2006 Audun Ytterdal, Jimmy Olsen, Tore Anderson, 
    748 Nicolai Langfeldt / Linpro AS. 
     619Nicolai Langfeldt. 
     620 
     621The work has in part been financed by Linpro AS. http://linpro.no/ 
    749622 
    750623This is free software; see the source for copying conditions. There is 
     
    756629=cut 
    757630 
     631 
    758632# vim:syntax=perl