Author: arkurth
Date: Wed Nov 18 16:20:53 2009
New Revision: 881826

URL: http://svn.apache.org/viewvc?rev=881826&view=rev
Log:
VCL-260
Added Windows.pm::set_file_owner() subroutine. Added calls to set root as the 
owner of /root in pre_capture() and post_load().

VCL-259
Added call to disable the ntsyslog service in Windows.pm::pre_capture(). This 
service was used to send event log messages to syslog on the management node 
and isn't used anymore. The service is no longer being properly configured and 
can cause problems if it attempts to send messages to an address it can't get 
to.

VCL-261
Reworked output/exit status checking in Windows.pm filesystem_entry_exists() so 
that it first checks if the output contains "file not found" rather than 
checking the exit status first. This should be more reliable.

VCL-269
Reworked Windows.pm::logoff_users() to check for disconnected sessions in 
addition to logged in sessions.

VCL-262
Updated Windows.pm::apply_security_templates() to use the "/overwrite /quiet" 
secedit.exe switches instead of "/verbose". This causes the .inf file being 
applied to overwrite existing settings rather than append to them. It is needed 
to remove the "log on as a service" permission from overwriting existing 
accounts with this permission.

Other:
Increased the amount of time Windows.pm::reboot() will wait for ping to respond 
from 4 to 6 minutes. 4 is too short under some circumstances.

Added check to Windows.pm::copy_capture_configuration_files() to check if the 
source configuration directory in .../tools on the management node exists 
before attempting to copy it to the node.

Added path to Windows.pm::clean_hard_drive(): /home/root/%USERPROFILE%. This 
directory is occasionally created by some Cygwin SSH operation. I'm not sure 
where it's coming from but the directory is not needed.

Modified:
    incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm

Modified: incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm
URL: 
http://svn.apache.org/viewvc/incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm?rev=881826&r1=881825&r2=881826&view=diff
==============================================================================
--- incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm (original)
+++ incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm Wed Nov 18 
16:20:53 2009
@@ -172,6 +172,17 @@
 
 =item *
 
+ Set root as the owner of /home/root
+
+=cut
+
+       if (!$self->set_file_owner('/home/root', 'root')) {
+               notify($ERRORS{'WARNING'}, 0, "unable to set root as the owner 
of /home/root");
+               return 0;
+       }
+
+=item *
+
  Copy the capture configuration files to the computer (scripts, utilities, 
drivers...)
 
 =cut
@@ -194,6 +205,17 @@
 
 =item *
 
+ Disable ntsyslog service if it exists on the computer - it can prevent Cygwin 
sshd from working
+
+=cut
+
+       if ($self->service_exists('ntsyslog') && 
!$self->set_service_startup_mode('ntsyslog', 'disabled')) {
+               notify($ERRORS{'WARNING'}, 0, "unable to set ntsyslog service 
startup mode to disabled");
+               return 0;
+       }
+
+=item *
+
  Disable IPv6
 
 =cut
@@ -452,6 +474,16 @@
 
 =item *
 
+ Set root as the owner of /home/root
+
+=cut
+
+       if (!$self->set_file_owner('/home/root', 'root')) {
+               notify($ERRORS{'WARNING'}, 0, "unable to set root as the owner 
of /home/root");
+       }
+
+=item *
+
  Set the Cygwin SSHD service startup mode to automatic
  
  The Cygwin SSHD service startup mode should be set to automatic after an image
@@ -1145,14 +1177,14 @@
        # Assemble the dir command and execute it
        my $dir_command = "cmd.exe /c dir /a /b \"$path\"";
        my ($dir_exit_status, $dir_output) = 
run_ssh_command($computer_node_name, $management_node_keys, $dir_command, '', 
'', 1);
-       if ((defined($dir_exit_status) && $dir_exit_status == 0) || 
(defined($dir_output) && grep(/$path/i, @$dir_output))) {
+       if (defined($dir_output) && grep(/file not found/i, @$dir_output)) {
+               notify($ERRORS{'DEBUG'}, 0, "filesystem entry does NOT exist on 
$computer_node_name: $path");
+               return 0;
+       }
+       elsif ((defined($dir_exit_status) && $dir_exit_status == 0) || 
(defined($dir_output) && grep(/$path/i, @$dir_output))) {
                notify($ERRORS{'DEBUG'}, 0, "filesystem entry exists on 
$computer_node_name: $path, dir output:\n" . join("\n", @$dir_output));
                return 1;
        }
-       elsif ((defined($dir_exit_status) && $dir_exit_status == 1) || 
(defined($dir_output) && grep(/file not found/i, @$dir_output))) {
-               notify($ERRORS{'DEBUG'}, 0, "filesystem entry does NOT exist on 
$computer_node_name: $path\noutput:\n" . join("\n", @$dir_output));
-               return 0;
-       }
        elsif ($dir_exit_status) {
                notify($ERRORS{'WARNING'}, 0, "failed to determine if 
filesystem entry exists on $computer_node_name: $path, exit status: 
$dir_exit_status, output:\...@{$dir_output}");
                return;
@@ -1165,6 +1197,69 @@
 
 #/////////////////////////////////////////////////////////////////////////////
 
+=head2 set_file_owner
+
+ Parameters  : file path, owner
+ Returns     : If successful: true
+               If failed: false
+ Description : Recursively sets the owner of the file path.  The file path can
+               be a file or directory. The owner must be a valid user account. 
A
+               group can optionally be specified by appending a semicolon and
+               the group name to the owner.
+               Examples:
+               set_file_owner('/home/root', 'root')
+               set_file_owner('/home/root', 'root:Administrators')
+
+=cut
+
+sub set_file_owner {
+       my $self = shift;
+       if (ref($self) !~ /windows/i) {
+               notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a 
function, it must be called as a class method");
+               return;
+       }
+       
+       # Get the file path argument
+       my $file_path = shift;
+       if (!$file_path) {
+               notify($ERRORS{'WARNING'}, 0, "file path argument was not 
specified");
+               return;
+       }
+       
+       # Get the owner argument
+       my $owner = shift;
+       if (!$owner) {
+               notify($ERRORS{'WARNING'}, 0, "owner argument was not 
specified");
+               return;
+       }
+
+       my $management_node_keys = $self->data->get_management_node_keys();
+       my $computer_node_name   = $self->data->get_computer_node_name();
+       
+       # Run chown
+       my ($chown_exit_status, $chown_output) = 
run_ssh_command($computer_node_name, $management_node_keys, "/usr/bin/chown.exe 
-R \"$owner\" \"$file_path\"", '', '', 0);
+       my @chown_errors = grep(/(chown:|cannot access|no such file|failed 
to)/ig, @$chown_output) if @$chown_output;
+       if (defined($chown_exit_status) && $chown_exit_status == 0 && 
!...@chown_errors) {
+               notify($ERRORS{'OK'}, 0, "set $owner as the owner of 
$file_path");
+       }
+       elsif (@chown_errors) {
+               notify($ERRORS{'WARNING'}, 0, "error occurred setting $owner as 
the owner of $file_path, error output:\n" . join("\n", @chown_errors));
+               return;
+       }
+       elsif ($chown_output) {
+               notify($ERRORS{'WARNING'}, 0, "error occurred setting $owner as 
the owner of $file_path, exit status: $chown_exit_status, 
output:\...@{$chown_output}");
+               return;
+       }
+       else {
+               notify($ERRORS{'WARNING'}, 0, "failed to run SSH command to set 
$owner as the owner of $file_path");
+               return;
+       }
+       
+       return 1;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
 =head2 logoff_users
 
  Parameters  :
@@ -1192,41 +1287,37 @@
                notify($ERRORS{'WARNING'}, 0, "failed to run qwinsta.exe SSH 
command on $computer_node_name");
                return;
        }
-
-       my @active_user_lines = grep(/Active/, @{$output});
-
-       return 1 if !...@active_user_lines;
-
-       notify($ERRORS{'OK'}, 0, "users are currently logged in on 
$computer_node_name:\...@active_user_lines");
-       #>rdp-tcp#1 root 0 Active rdpwd
-       foreach my $active_user_line (@active_user_lines) {
-               $active_user_line =~ /[\s>]*(\S+)\s+(.*\w)\s*(\d+)\s+Active.*/;
-               my $session_name = $1;
-               my $username     = $2;
-               my $session_id   = $3;
-
-               notify($ERRORS{'DEBUG'}, 0, "user logged in: $username, session 
name: $session_name, session id: $session_id");
-               #$ logoff /?
-               #Terminates a session.
+       
+       # Find lines with the state = Active or Disc
+       # Disc will occur if the user disconnected the RDP session but didn't 
logoff
+       my @connection_lines = grep(/(Active|Disc)/, @{$output});
+       return 1 if !...@connection_lines;
+       
+       #notify($ERRORS{'OK'}, 0, "connections on 
$computer_node_name:\...@connection_lines");
+       #  SESSIONNAME        USERNAME                 ID  STATE   TYPE        
DEVICE
+       # '>                  root                      0  Disc    rdpwd        
       '
+       # '>rdp-tcp#24        root                      0  Active  rdpwd        
       '
+       foreach my $connection_line (@connection_lines) {
+               my ($session_id) = $connection_line =~ 
/(\d+)\s+(?:Active|Listen|Conn|Disc)/g;
+               notify($ERRORS{'DEBUG'}, 0, "qwinsta.exe output:\nline: 
'$connection_line'\nsession id: '$session_id'");
+               
                #LOGOFF [sessionname | sessionid] [/SERVER:servername] [/V]
                #  sessionname         The name of the session.
                #  sessionid           The ID of the session.
                #  /SERVER:servername  Specifies the Terminal server containing 
the user
                #                                                        
session to log off (default is current).
                #  /V                  Displays information about the actions 
performed.
-
-               # Call logoff.exe, pass it the session name
-               # Session ID fails if the ID is 0
-               my ($logoff_exit_status, $logoff_output) = 
run_ssh_command($computer_node_name, $management_node_keys, "logoff.exe 
$session_name /V");
+               # Call logoff.exe, pass it the session
+               my ($logoff_exit_status, $logoff_output) = 
run_ssh_command($computer_node_name, $management_node_keys, "logoff.exe 
\"$session_id\" /V");
                if ($logoff_exit_status == 0) {
-                       notify($ERRORS{'OK'}, 0, "logged off user: $username");
+                       notify($ERRORS{'OK'}, 0, "logged off session ID: 
$session_id, output:\n" . join("\n", @$logoff_output));
                }
                else {
-                       notify($ERRORS{'WARNING'}, 0, "failed to log off user: 
$username, exit status: $logoff_exit_status, output:\...@{$logoff_output}");
+                       notify($ERRORS{'WARNING'}, 0, "failed to log off 
session ID: $session_id, exit status: $logoff_exit_status, 
output:\...@{$logoff_output}");
                }
-       } ## end foreach my $active_user_line (@active_user_lines)
+       }
        return 1;
-} ## end sub logoff_users
+}
 
 #/////////////////////////////////////////////////////////////////////////////
 
@@ -2797,8 +2888,8 @@
                notify($ERRORS{'DEBUG'}, 0, "$computer_node_name reboot has 
begun, sleeping for 15 seconds");
                sleep 15;
 
-               # Wait maximum of 4 minutes for the computer to come back up
-               if (!$self->wait_for_ping(4)) {
+               # Wait maximum of 6 minutes for the computer to come back up
+               if (!$self->wait_for_ping(6)) {
                        # Check if the computer was ever offline, it should 
have been or else reboot never happened
                        notify($ERRORS{'WARNING'}, 0, "$computer_node_name 
never responded to ping");
                        next WAIT_ATTEMPT;
@@ -5912,6 +6003,12 @@
 
        # Copy configuration files
        for my $source_configuration_directory 
(@source_configuration_directories) {
+               # Check if source configuration directory exists on this 
management node
+               unless (-d "$source_configuration_directory") {
+                       notify($ERRORS{'OK'}, 0, "source directory does not 
exist on this management node: $source_configuration_directory");
+                       next;
+               }
+               
                notify($ERRORS{'OK'}, 0, "copying image capture configuration 
files from $source_configuration_directory to $computer_node_name");
                if (run_scp_command("$source_configuration_directory/*", 
"$computer_node_name:$NODE_CONFIGURATION_DIRECTORY", $management_node_keys)) {
                        notify($ERRORS{'OK'}, 0, "copied 
$source_configuration_directory directory to 
$computer_node_name:$NODE_CONFIGURATION_DIRECTORY");
@@ -6227,6 +6324,7 @@
                '$SYSTEMDRIVE/Documents and Settings,.*Temp\\/.*,10',
                '$SYSTEMDRIVE/Documents and Settings,.*Temporary Internet 
Files\\/Content.*\\/.*,10',
                '$SYSTEMDRIVE,.*pagefile\\.sys,1',
+               '$SYSTEMDRIVE/cygwin/home/root,.*%USERPROFILE%,1',
        );
 
        # Attempt to stop the AFS service, needed to delete AFS files
@@ -6836,7 +6934,7 @@
                        notify($ERRORS{'DEBUG'}, 0, "copied file: 
$computer_node_name:$inf_target_path");
        
                        # Set permission on the copied file
-                       if (!run_ssh_command($computer_node_name, 
$management_node_keys, "/usr/bin/chmod.exe -R 644 $inf_target_path", '', '', 
1)) {
+                       if (!run_ssh_command($computer_node_name, 
$management_node_keys, "/usr/bin/chmod.exe -R 644 $inf_target_path", '', '', 
0)) {
                                notify($ERRORS{'WARNING'}, 0, "could not set 
permissions on $inf_target_path");
                        }
                }
@@ -6850,16 +6948,22 @@
                my $secedit_db = '$SYSTEMROOT/security/Database/' . 
"$inf_count\_$inf_file_root.sdb";
                my $secedit_log = '$SYSTEMROOT/security/Logs/' . 
"$inf_count\_$inf_file_root.log";
                
+               # Attempt to delete an existing log file
+               $self->delete_file($secedit_log);
+               
                # The inf path must use backslashes or secedit.exe will fail
                $inf_target_path =~ s/\//\\\\/g;
                
-               my $secedit_command = "$secedit_exe /configure /cfg 
\"$inf_target_path\" /db $secedit_db /log $secedit_log /verbose";
+               # Run secedit.exe
+               # Note: secedit.exe returns exit status 3 if a warning occurs, 
this will appear in the log file:
+               # Task is completed. Warnings occurred for some attributes 
during this operation. It's ok to ignore.
+               my $secedit_command = "$secedit_exe /configure /cfg 
\"$inf_target_path\" /db $secedit_db /log $secedit_log /overwrite /quiet";
                my ($secedit_exit_status, $secedit_output) = 
run_ssh_command($computer_node_name, $management_node_keys, $secedit_command, 
'', '', 0);
-               if (defined($secedit_exit_status) && $secedit_exit_status == 0) 
{
+               if (defined($secedit_exit_status) && ($secedit_exit_status == 0 
|| $secedit_exit_status == 3)) {
                        notify($ERRORS{'OK'}, 0, "ran secedit.exe to apply 
$inf_file_name");
                }
                elsif (defined($secedit_exit_status)) {
-                       notify($ERRORS{'WARNING'}, 0, "failed to run 
secedit.exe to apply $inf_target_path, exit status: $secedit_exit_status, 
output:\...@{$secedit_output}");
+                       notify($ERRORS{'WARNING'}, 0, "failed to run 
secedit.exe to apply $inf_target_path, exit status: $secedit_exit_status, 
output:\n" . join("\n", @$secedit_output));
                        $error_occurred++;
                }
                else {


Reply via email to