Code

Some fixes when operating on loopback device.
[gosa.git] / gosa-si / gosa-si-client
index 3ae58a5813c42c561edfb1266eb6e0ebf18261cc..2d9ce606325c9941e5036da1fd3fda7b7c8906cf 100755 (executable)
@@ -8,7 +8,7 @@
 #  DESCRIPTION:
 #
 #      OPTIONS:  ---
-# REQUIREMENTS:  ---
+# REQUIREMENTS:  libnetaddr-ip-perl
 #         BUGS:  ---
 #        NOTES:
 #       AUTHOR:   (Andreas Rettenberger), <rettenberger@gonicus.de>
@@ -24,6 +24,7 @@ use Getopt::Long;
 use Config::IniFiles;
 use POSIX;
 use Time::HiRes qw( gettimeofday );
+use File::Basename;
 
 use Fcntl;
 use IO::Socket::INET;
@@ -35,18 +36,18 @@ use Data::Dumper;
 use Sys::Syslog qw( :DEFAULT setlogsock);
 use File::Spec;
 use Cwd;
-use NetAddr::IP::Lite;
+use NetAddr::IP;
 use GOSA::GosaSupportDaemon;
 
 
 my ($cfg_file, %cfg_defaults, $foreground, $verbose, $pid_file, $procid, $pid, $log_file);
 my ($server_address, $server_ip, $server_port, $server_domain, $server_passwd, $server_cipher, $server_timeout);
-my ($client_address, $client_ip, $client_port, $client_mac_address, $network_interface, $ldap_config, $pam_config, $nss_config);
+my ($client_address, $client_ip, $client_port, $client_mac_address, $network_interface, $ldap_config, $pam_config, $nss_config, $gotoHardwareChecksum);
 my ($input_socket, $rbits, $wbits, $ebits, $xml, $known_hosts, $ldap_enabled);
 my (@events);
 
 # default variables
-my $event_dir = "/etc/gosa-si/client/events";
+my $event_dir = "/usr/lib/gosa-si/client/events";
 $known_hosts = {};
 $foreground = 0 ;
 %cfg_defaults =
@@ -57,6 +58,7 @@ $foreground = 0 ;
 "client" => 
     {"client_port" => [\$client_port, "20083"],
      "client_ip" => [\$client_ip, "0.0.0.0"],
+        "client_mac_address" => [\$client_mac_address, "00:00:00:00:00:00"],
      "ldap" => [\$ldap_enabled, 1],
      "ldap_config" => [\$ldap_config, "/etc/ldap/ldap.conf"],
      "pam_config" => [\$pam_config, "/etc/pam_ldap.conf"],
@@ -142,13 +144,12 @@ sub daemon_log {
 sub check_cmdline_param () {
     my $err_config;
     my $err_counter = 0;
-    if( not defined( $cfg_file)) {
-        #$err_config = "please specify a config file";
-        #$err_counter += 1;
-        my $cwd = getcwd;
-        my $name = "/etc/gosa-si/client.conf";
-        $cfg_file = File::Spec->catfile( $cwd, $name );
-        print STDERR "no conf file specified\n   try to use default: $cfg_file\n";        
+       if(not defined($cfg_file)) {
+               $cfg_file = "/etc/gosa-si/client.conf";
+               if(! -r $cfg_file) {
+                       $err_config = "please specify a config file";
+                       $err_counter += 1;
+               }
     }
     if( $err_counter > 0 ) {
         &usage( "", 1 );
@@ -271,38 +272,39 @@ sub get_interfaces {
 #  DESCRIPTION:  Uses ioctl to get mac address directly from system.
 #===============================================================================
 sub get_mac {
-        my $ifreq= shift;
-        my $result;
-        if ($ifreq && length($ifreq) > 0) { 
-                if($ifreq eq "all") {
+       my $ifreq= shift;
+       my $result;
+       
+       if ($ifreq && length($ifreq) > 0) { 
+               if($ifreq eq "all") {
                        if(defined($server_ip)) {
                                $result = &get_local_mac_for_remote_ip($server_ip);
+                       } elsif ($client_mac_address && length($client_mac_address) > 0) {
+                               $result = $client_mac_address;
                        } else {
                                $result = "00:00:00:00:00:00";
                        }
-                } else {
-                        my $SIOCGIFHWADDR= 0x8927;     # man 2 ioctl_list
-
-                        # A configured MAC Address should always override a guessed value
-                        if ($client_mac_address and length($client_mac_address) > 0) {
-                                $result= $client_mac_address;
-                        }
-
-                        socket SOCKET, PF_INET, SOCK_DGRAM, getprotobyname('ip')
-                                or die "socket: $!";
-
-                        if(ioctl SOCKET, $SIOCGIFHWADDR, $ifreq) {
-                                my ($if, $mac)= unpack 'h36 H12', $ifreq;
-
-                                if (length($mac) > 0) {
-                                        $mac=~ m/^([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])$/;
-                                        $mac= sprintf("%s:%s:%s:%s:%s:%s", $1, $2, $3, $4, $5, $6);
-                                        $result = $mac;
-                                }
-                        }
-                }
-        }
-        return $result;
+               } else {
+                       my $SIOCGIFHWADDR= 0x8927;     # man 2 ioctl_list
+
+                       socket SOCKET, PF_INET, SOCK_DGRAM, getprotobyname('ip')
+                               or die "socket: $!";
+                       
+                       # A configured MAC Address should always override a guessed value
+                       if ($client_mac_address and length($client_mac_address) > 0) {
+                               $result = $client_mac_address;
+                       } elsif(ioctl SOCKET, $SIOCGIFHWADDR, $ifreq) {
+                               my ($if, $mac)= unpack 'h36 H12', $ifreq;
+
+                               if (length($mac) > 0) {
+                                       $mac=~ m/^([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])$/;
+                                       $mac= sprintf("%s:%s:%s:%s:%s:%s", $1, $2, $3, $4, $5, $6);
+                                       $result = $mac;
+                               }
+                       }
+               }
+       }
+       return $result;
 }
 
 #===  FUNCTION  ================================================================
@@ -363,7 +365,7 @@ sub get_local_mac_for_remote_ip {
                $destination= sprintf("%d.%d.%d.%d", hex($a), hex($b), hex($c), hex($d));
                ($d,$c,$b,$a)=unpack('a2 a2 a2 a2', $Mask);
                $mask= sprintf("%d.%d.%d.%d", hex($a), hex($b), hex($c), hex($d));
-               if(new NetAddr::IP::Lite($server_ip)->within(new NetAddr::IP::Lite($destination, $mask))) {
+               if(new NetAddr::IP($server_ip)->within(new NetAddr::IP($destination, $mask))) {
                        # destination matches route, save mac and exit
                        $result= &get_mac($Iface);
                        last;
@@ -454,14 +456,14 @@ sub register_at_server {
     opendir(DIR, $event_dir) 
         or daemon_log("cannot find directory $event_dir!\ngosa-si-client starts without any accepting events!", 1);
     my $file_name;
-    @events = ();
+    my @events_list = ();
     while(defined($file_name = readdir(DIR))){
         if ($file_name eq "." || $file_name eq "..") {
             next;
         }
-        push(@events, $file_name);
+        push(@events_list, $file_name);
     }
-    my $events = join(",", @events);
+    my $events = join(",", @events_list);
     daemon_log("found events: $events", 1);
 
     # fill in all possible servers
@@ -482,13 +484,12 @@ sub register_at_server {
     my ($rout, $wout, $reg_server);
     foreach my $server (@servers) {
 
-# TODO : server abhängige macadress und ipadresse eintragen
-
         # create msg hash
         my $register_hash = &create_xml_hash("here_i_am", $client_address, $server);
         &add_content2xml_hash($register_hash, "new_passwd", $new_server_passwd);
         &add_content2xml_hash($register_hash, "mac_address", $client_mac_address);
         &add_content2xml_hash($register_hash, "events", $events);
+        &add_content2xml_hash($register_hash, "gotoHardwareChecksum", $gotoHardwareChecksum);
 
         # send xml hash to server with general server passwd
         my $answer = &send_msg_hash2address($register_hash, $server, $server_passwd);
@@ -971,11 +972,7 @@ sub process_incoming_msg {
 
     my $header = @{$msg_hash->{header}}[0];
     
-    daemon_log("recieve '$header' from $host", 1);
-#    daemon_log("header from msg:", 1);
-#    daemon_log("\t$header", 1);
-#    daemon_log("msg to process:", 7);
-#    daemon_log("\t$msg", 7);
+    daemon_log("receive '$header' from $host", 1);
 
     #check whether msg to process is a event 
     opendir(DIR, $event_dir) 
@@ -1008,6 +1005,7 @@ sub process_incoming_msg {
     elsif ($header eq 'ping') { &got_ping($msg_hash) }
     elsif ($header eq 'wake_up') { &execute_event($msg_hash)}
     elsif ($header eq 'new_passwd') { &new_passwd()}
+       elsif ($header eq 'detect_hardware') { &detect_hardware()}
     else { daemon_log("ERROR: no function assigned to msg $header", 5) }
 
     return;
@@ -1081,6 +1079,9 @@ sub new_ldap_config {
     my @nss_options;
     my $goto_admin;
     my $goto_secret;
+    my $admin_base= "";
+    my $department= "";
+    my $unit_tag;
 
     # Transform input into array
     while ( my ($key, $value) = each(%$msg_hash) ) {
@@ -1117,9 +1118,28 @@ sub new_ldap_config {
                        push (@nss_options, "$element");
                        next;
                }
+               if ($key =~ /^admin_base$/) {
+                       $admin_base= $element;
+                       next;
+               }
+               if ($key =~ /^department$/) {
+                       $department= $element;
+                       next;
+               }
+               if ($key =~ /^unit_tag$/) {
+                       $unit_tag= $element;
+                       next;
+               }
        }
     }
 
+    # Unit tagging enabled?
+    if (defined $unit_tag){
+           push (@pam_options, "pam_filter gosaUnitTag=$unit_tag");
+           push (@nss_options, "nss_base_passwd  $admin_base?sub?gosaUnitTag=$unit_tag");
+           push (@nss_options, "nss_base_group   $admin_base?sub?gosaUnitTag=$unit_tag");
+    }
+
     # Setup ldap.conf
     my $file1;
     my $file2;
@@ -1160,18 +1180,31 @@ sub new_ldap_config {
     close (file1);
     daemon_log("wrote $pam_config", 5);
 
-    # Create goto.secrets if told so
+    # Create goto.secrets if told so - for compatibility reasons
     if (defined $goto_admin){
            open(file1, "> /etc/goto/secret");
            close(file1);
            chown(0,0, "/etc/goto/secret");
            chmod(0600, "/etc/goto/secret");
            open(file1, "> /etc/goto/secret");
-           print file1 $goto_admin.":".$goto_secret."\n";
+           print file1 "GOTOADMIN=\"$goto_admin\"\nGOTOSECRET=\"$goto_secret\"\n";
            close(file1);
            daemon_log("wrote /etc/goto/secret", 5);
     }
 
+    
+
+    # Write shell based config
+    my $cfg_name= dirname($ldap_config)."/ldap-shell.conf";
+    open(file1, "> $cfg_name");
+    print file1 "LDAP_BASE=\"$ldap_base\"\n";
+    print file1 "ADMIN_BASE=\"$admin_base\"\n";
+    print file1 "DEPARTMENT=\"$department\"\n";
+    print file1 "UNIT_TAG=\"".(defined $unit_tag ? "$unit_tag" : "")."\"\n";
+    print file1 "UNIT_TAG_FILTER=\"".(defined $unit_tag ? "(gosaUnitTag=$unit_tag)" : "")."\"\n";
+    close(file1);
+    daemon_log("wrote $cfg_name", 5);
+
     return;
 
 }
@@ -1236,8 +1269,126 @@ sub new_passwd {
     return; 
 }
 
+sub generate_hw_digest {
+       my $hw_data;
+       foreach my $line (split /\n/, `cat /proc/bus/pci/devices`) {
+               $hw_data.= sprintf "%s", $line =~ /[^\s]+\s([^\s]+)\s.*/;
+       }
+       return(md5_base64($hw_data));
+}
 
+sub detect_hardware {
+       my $hwinfo= `which hwinfo`;
+       chomp $hwinfo;
 
+       if (!(defined($hwinfo) && length($hwinfo) > 0)) {
+               &main::daemon_log("ERROR: hwinfo was not found in \$PATH! Hardware detection will not work!", 1);
+               return;
+       }
+
+       my $result= {
+               macAddress      => $client_mac_address,
+               gotoXMonitor    => "",
+               gotoXDriver     => "",
+               gotoXMouseType  => "",
+               gotoXMouseport  => "",
+               gotoXkbModel    => "",
+               gotoXHsync      => "",
+               gotoXVsync      => "",
+               gotoXResolution => "",
+               ghUsbSupport    => "",
+               gotoSndModule   => "",
+               ghGfxAdapter    => "",
+               ghNetNic        => "",
+               ghSoundAdapter  => "",
+               ghMemSize       => "",
+               ghCpuType       => "",
+               gotoModules     => [],
+               ghIdeDev        => [],
+               ghScsiDev       => [],
+       };
+
+       &main::daemon_log("Starting hardware detection", 4);
+       my $gfxcard= `$hwinfo --gfxcard`;
+       my $primary_adapter= $1 if $gfxcard =~ /^Primary display adapter:\s#(\d+)\n/m;
+       if(defined($primary_adapter)) {
+               ($result->{ghGfxAdapter}, $result->{gotoXDriver}) = ($1,$2) if 
+                       $gfxcard =~ /$primary_adapter:.*?Model:\s\"([^\"]*)\".*?Server Module:\s(\w*).*?\n\n/s;
+       }
+       my $monitor= `$hwinfo --monitor`;
+       my $primary_monitor= $1 if $monitor =~ /^(\d*):.*/m;
+       if(defined($primary_monitor)) {
+               ($result->{gotoXMonitor}, $result->{gotoXResolution}, $result->{gotoXVsync}, $result->{gotoXHsync})= ($1,$2,$3,$4) if 
+               $monitor =~ /$primary_monitor:\s.*?Model:\s\"(.*?)\".*?Max\.\sResolution:\s([0-9x]*).*?Vert\.\sSync\sRange:\s([\d\-]*)\sHz.*?Hor\.\sSync\sRange:\s([\d\-]*)\skHz.*/s;
+       }
+
+       if(length($result->{gotoXHsync}) == 0) {
+               # set default values
+               $result->{gotoXHsync} = "30+50";
+               $result->{gotoXVsync} = "30+90";
+       }
+
+       my $mouse= `$hwinfo --mouse`;
+       my $primary_mouse= $1 if $mouse =~ /^(\d*):.*/m;
+       if(defined($primary_mouse)) {
+               ($result->{gotoXMouseport}, $result->{gotoXMouseType}) = ($1,$2) if
+               $mouse =~ /$primary_mouse:\s.*?Device\sFile:\s(.*?)\s.*?XFree86\sProtocol:\s(.*?)\n.*?/s;
+       }
+
+       my $sound= `$hwinfo --sound`;
+       my $primary_sound= $1 if $sound =~ /^(\d*):.*/m;
+       if(defined($primary_sound)) {
+               ($result->{ghSoundAdapter}, $result->{gotoSndModule})= ($1,$2) if 
+               $sound =~ /$primary_sound:\s.*?Model:\s\"(.*?)\".*?Driver\sModules:\s\"(.*?)\".*/s;
+       }
+
+       my $netcard= `hwinfo --netcard`;
+       my $primary_netcard= $1 if $netcard =~ /^(\d*):.*/m;
+       if(defined($primary_netcard)) {
+               $result->{ghNetNic}= $1 if $netcard =~ /$primary_netcard:\s.*?Model:\s\"(.*?)\".*/s;
+       }
+
+       my $keyboard= `hwinfo --keyboard`;
+       my $primary_keyboard= $1 if $keyboard =~ /^(\d*):.*/m;
+       if(defined($primary_keyboard)) {
+               $result->{gotoXkbModel}= $1 if $keyboard =~ /$primary_keyboard:\s.*?XkbModel:\s(.*?)\n.*/s;
+       }
+
+       $result->{ghCpuType}= sprintf "%s / %s - %s", 
+       `cat /proc/cpuinfo` =~ /.*?vendor_id\s+:\s(.*?)\n.*?model\sname\s+:\s(.*?)\n.*?cpu\sMHz\s+:\s(.*?)\n.*/s;
+       $result->{ghMemSize}= $1 if `cat /proc/meminfo` =~ /^MemTotal:\s+(.*?)\skB.*/s;
+
+       my @gotoModules=();
+       for my $line(`lsmod`) {
+               if (($line =~ /^Module.*$/) or ($line =~ /^snd.*$/)) {
+                       next;
+               } else {
+                       push @gotoModules, $1 if $line =~ /^(\w*).*$/
+               }
+       }
+       my %seen = ();
+       
+       # Remove duplicates and save
+       push @{$result->{gotoModules}}, grep { ! $seen{$_} ++ } @gotoModules;
+
+       $result->{ghUsbSupport} = (-d "/proc/bus/usb")?"true":"false";
+       
+       foreach my $device(`hwinfo --ide` =~ /^.*?Model:\s\"(.*?)\".*$/mg) {
+               push @{$result->{ghIdeDev}}, $device;
+       }
+
+       foreach my $device(`hwinfo --scsi` =~ /^.*?Model:\s\"(.*?)\".*$/mg) {
+               push @{$result->{ghScsiDev}}, $device;
+       }
+
+       &main::daemon_log("Hardware detection done!", 4);
+
+    return &send_msg_hash2address(
+               &create_xml_hash("detected_hardware", $client_address, $server_address, $result),
+               $server_address, 
+               $server_passwd
+       );
+}
 
 #==== MAIN = main ==============================================================
 
@@ -1254,10 +1405,11 @@ GetOptions("h|help" => \&usage,
 &read_configfile;
 &check_pid;
 
-
-open STDIN, ‘/dev/null’ or die “Can’t read /dev/null: $!”;
-open STDOUT, ‘>>/dev/null’ or die “Can’t write to /dev/null: $!”;
-open STDERR, ‘>>/dev/null’ or die “Can’t write to /dev/null: $!”;
+if ( ! $foreground ) {
+       open STDIN, '/dev/null' or die "Can’t read /dev/null: $!";
+       open STDOUT, '>>/dev/null' or die "Can't write to /dev/null: $!";
+       open STDERR, '>>/dev/null' or die "Can't write to /dev/null: $!";
+}
 
 
 # restart daemon log file
@@ -1292,11 +1444,19 @@ daemon_log("client mac address detected: $client_mac_address", 1);
 if (defined $server_ip && defined $server_port) {
     $server_address = $server_ip.":".$server_port;
 }
+
+# this is necessary that gosa-si-server knowns to which ip-address he can send msgs
+if( $client_ip eq "0.0.0.0" ) {
+    $client_ip = "127.0.0.1";
+}
 $client_address = $client_ip.":".$client_port;
 
 # setup xml parser
 $xml = new XML::Simple();
 
+# compute hardware checksum
+$gotoHardwareChecksum= &generate_hw_digest();
+
 # create input socket
 daemon_log(" ", 1);
 $rbits = $wbits = $ebits = "";