Author: arkurth
Date: Tue Jun  6 16:09:58 2017
New Revision: 1797800

URL: http://svn.apache.org/viewvc?rev=1797800&view=rev
Log:
VCL-867
Renamed Windows.pm::ad_join to ad_join_ps to differentiate it from the 
experimental ad_join_wmic.

Fixed problems with passwords containing special characters in ad_join_ps. 
Single quotes are now escaped.

Added debugging output to the script generated in ad_join_ps and ad_search.

Replaced utils.pm::get_active_directory_domain_credentials with 
get_management_node_ad_domain_credentials, called from 
DataStructure.pm::get_domain_credentials.

Added DataStructure.pm::get_domain_credentials, called from 
Windows.pm::ad_search instead of 
utils.pm::get_active_directory_domain_credentials. When retrieving credentials 
for a domain other than one assigned to the image of the current reservation, 
VCL object access is required to decrypt the password.


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

Modified: vcl/trunk/managementnode/lib/VCL/DataStructure.pm
URL: 
http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/DataStructure.pm?rev=1797800&r1=1797799&r2=1797800&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/DataStructure.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/DataStructure.pm Tue Jun  6 16:09:58 2017
@@ -2797,7 +2797,44 @@ sub get_image_domain_password {
                return;
        }
        
-       return $self->mn_os->decrypt_cryptsecret($secret_id, 
$encrypted_password);
+       my $image_domain_password = 
$self->mn_os->decrypt_cryptsecret($secret_id, $encrypted_password);
+       #notify($ERRORS{'DEBUG'}, 0, string_to_ascii($image_domain_password));
+       return $image_domain_password;
+}
+
+#//////////////////////////////////////////////////////////////////////////////
+
+=head2 get_domain_credentials
+
+ Parameters  : $domain_identifier
+ Returns     : array ($username, $domain_password)
+ Description : Attempts to determine and decrypt the username and password for
+               the domain specified by the argument. 
+
+=cut
+
+sub get_domain_credentials {
+       my $self = shift;
+       if (ref($self) !~ /VCL::/i) {
+               notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a 
function, it must be called as a class method");
+               return 0;
+       }
+       
+       my $domain_identifier = shift;
+       if (!defined($domain_identifier)) {
+               notify($ERRORS{'WARNING'}, 0, "domain identifier argument was 
not supplied");
+               return;
+       }
+       
+       my $management_node_id = $self->get_management_node_id();
+       
+       my ($username, $secret_id, $encrypted_password) = 
get_management_node_ad_domain_credentials($management_node_id, 
$domain_identifier);
+       return unless $username && $secret_id && $encrypted_password;
+       
+       my $domain_password = $self->mn_os->decrypt_cryptsecret($secret_id, 
$encrypted_password) || return;
+       
+       notify($ERRORS{'DEBUG'}, 0, "retrieved credentials for Active Directory 
domain:\nusername: '$username'\npassword: '$domain_password'");
+       return ($username, $domain_password);
 }
 
 #//////////////////////////////////////////////////////////////////////////////

Modified: vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm
URL: 
http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm?rev=1797800&r1=1797799&r2=1797800&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm Tue Jun  6 16:09:58 
2017
@@ -13243,8 +13243,8 @@ sub run_powershell_command {
  Description : Accepts a string containing the contents of a Powershell script,
                creates the script on the computer under C:\cygwin\VCL\Scripts,
                and executes the script. The script is named after the calling
-               subroutine, so ad_join.ps1 would be generated when invoked from
-               ad_join().
+               subroutine, so ad_join_ps.ps1 would be generated when invoked 
from
+               ad_join_ps().
                
                By default, the script file is deleted after it is executed for
                safety. This can be overridden if the $retain_script_file
@@ -13556,7 +13556,7 @@ sub ad_check {
        if (!$computer_current_domain_name) {
                # Computer is not joined to an AD domain, return the result of 
attempting to join
                notify($ERRORS{'OK'}, 0, "image is configured to join the 
$image_domain_dns_name domain, $computer_name is not joined to a domain, 
attempting to join the domain");
-               return $self->ad_join();
+               return $self->ad_join_ps();
        }
        
        
@@ -13568,7 +13568,7 @@ sub ad_check {
                        notify($ERRORS{'WARNING'}, 0, "image is configured to 
join the $image_domain_dns_name, failed to unjoin $computer_name from the 
$computer_current_domain_name domain, returning undefined");
                        return;
                }
-               elsif (!$self->ad_join()) {
+               elsif (!$self->ad_join_ps()) {
                        notify($ERRORS{'WARNING'}, 0, "image is configured to 
join the $image_domain_dns_name, unjoined $computer_name from the incorrect 
$computer_current_domain_name domain but failed to rejoin the correct 
$image_domain_dns_name domain, returning undefined");
                        return;
                }
@@ -13618,7 +13618,7 @@ sub ad_check {
                notify($ERRORS{'WARNING'}, 0, "failed to unjoin $computer_name 
from the $computer_current_domain_name domain in order to rejoin in the correct 
OU, returning undefined");
                return;
        }
-       elsif (!$self->ad_join()) {
+       elsif (!$self->ad_join_ps()) {
                notify($ERRORS{'WARNING'}, 0, "failed to rejoin $computer_name 
to the correct OU in the $image_domain_dns_name domain: '$image_ou_dn', 
returning undefined");
                return;
        }
@@ -13630,7 +13630,7 @@ sub ad_check {
 
 #//////////////////////////////////////////////////////////////////////////////
 
-=head2 ad_join
+=head2 ad_join_ps
 
  Parameters  : none
  Returns     : boolean
@@ -13639,7 +13639,7 @@ sub ad_check {
 
 =cut
 
-sub ad_join {
+sub ad_join_ps {
        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");
@@ -13657,7 +13657,6 @@ sub ad_join {
        my $domain_dns_name = $self->data->get_image_domain_dns_name();
        my $domain_username = $self->data->get_image_domain_username();
        my $domain_password = $self->data->get_image_domain_password();
-       
        my $computer_ou_dn = $self->get_ad_computer_ou_dn();
        
        if (!defined($domain_dns_name)) {
@@ -13676,26 +13675,24 @@ sub ad_join {
        # Figure out/fix the computer OU and assemble optional section to add 
to PowerShell command
        my $domain_computer_command_section = '';
        if ($computer_ou_dn) {
-               $domain_computer_command_section = "-OUPath 
\"$computer_ou_dn\"";
+               $domain_computer_command_section = "-OUPath '$computer_ou_dn'";
        }
        
        my $domain_user_string = "$domain_username\@$domain_dns_name";
        
+       # Escape single quotes by doubling them
+       (my $domain_password_escaped = $domain_password) =~ s/(['])/$1$1/g;
+       
        notify($ERRORS{'DEBUG'}, 0, "attempting to join $computer_name to AD\n" 
.
                "domain DNS name    : $domain_dns_name\n" .
                "domain user string : $domain_user_string\n" .
-               "domain password    : $domain_password\n" .
+               "domain password    : $domain_password (escaped: 
$domain_password_escaped)\n" .
                "domain computer OU : " . ($computer_ou_dn ? $computer_ou_dn : 
'<not configured>')
        );
        
        # Perform preparation tasks
        $self->ad_join_prepare() || return;
        
-       # Assemble the PowerShell script
-       my $ad_powershell_script;
-       $ad_powershell_script .= "\$ps_credential = New-Object 
System.Management.Automation.PsCredential(\"$domain_user_string\", 
(ConvertTo-SecureString \"$domain_password\" -AsPlainText -Force))\n";
-       $ad_powershell_script .= "Add-Computer -DomainName \"$domain_dns_name\" 
-Credential \$ps_credential $domain_computer_command_section -Verbose 
-ErrorAction Stop\n";
-       
        # Note: commented out because this isn't consistently working
        # The rename occasionally fails with 'The directory service is busy.'
        # Check if the computer needs to be renamed
@@ -13728,8 +13725,24 @@ sub ad_join {
        #}
        
        
+       # Assemble the PowerShell script
+       my $ad_powershell_script = <<EOF;
+\$Host.UI.RawUI.BufferSize = New-Object Management.Automation.Host.Size(5000, 
500)
+Clear-Host
+\$username = '$domain_user_string'
+\$password = '$domain_password_escaped'
+Write-Host "username (between >*<): `n>\$username<`n"
+Write-Host "password (between >*<): `n>\$password<`n"
+\$ps_credential = New-Object 
System.Management.Automation.PsCredential(\$username, (ConvertTo-SecureString 
\$password -AsPlainText -Force))
+Add-Computer -DomainName '$domain_dns_name' -Credential \$ps_credential 
$domain_computer_command_section -Verbose -ErrorAction Stop
+EOF
        
-       notify($ERRORS{'DEBUG'}, 0, "PowerShell script 
contents:\n$ad_powershell_script");
+       notify($ERRORS{'DEBUG'}, 0, "attempting to join $computer_name to 
$domain_dns_name domain using PowerShell script:\n$ad_powershell_script");
+       my ($exit_status, $output) = 
$self->run_powershell_as_script($ad_powershell_script, 0, 0); # (path, show 
output, retain file)
+       if (!defined($output)) {
+               notify($ERRORS{'WARNING'}, 0, "failed to execute PowerShell 
script to join $computer_name to Active Directory domain");
+               return;
+       }
        
        # Success:
        # WARNING: The changes will take effect after you restart the computer
@@ -13737,7 +13750,7 @@ sub ad_join {
        
        # Possible errors:
        
-       # File C:\Users\Administrator\Desktop\ad_join.ps1 cannot be loaded 
because
+       # File C:\Users\Administrator\Desktop\ad_join_ps.ps1 cannot be loaded 
because
        # the execution of scripts is disabled on this system. Please see 
"get-help
        # about_signing" for more details.
        
@@ -13755,46 +13768,60 @@ sub ad_join {
        # Add-Computer : This command cannot be executed on target
        # computer('VCLV98-247') due to following error: The account already 
exists.
        
-       my ($exit_status, $output) = 
$self->run_powershell_as_script($ad_powershell_script, 0, 1);
-       if (!defined($output)) {
-               notify($ERRORS{'WARNING'}, 0, "failed to execute PowerShell 
script to join $computer_name to Active Directory domain");
-               return;
-       }
-       
-       # Combine the output lines into a single string or else unpredictable 
text wrapping may occur
-       my $output_string = join(' ', @$output);
-       $output_string =~ s/\s+/ /g;
-       
-       if ($output_string =~ /(error:|does not exist|cannot be loaded)/i) {
-               notify($ERRORS{'WARNING'}, 0, "failed to join $computer_name to 
Active Directory domain, output:\n$output_string");
+       my $reboot_after_join = 1;
+       if (grep(/(failed to join|error:|does not exist|cannot be loaded)/i, 
@$output)) {
+               notify($ERRORS{'WARNING'}, 0, "failed to join $computer_name to 
Active Directory domain, output:\n" . join("\n", @$output));
                return 0;
        }
+       elsif (grep(/already in that domain/i, @$output)) {
+               # Add-Computer : Cannot add computer '<hostname>' to domain 
'<domain DNS name>' because it is already in that domain.
+               notify($ERRORS{'OK'}, 0, "$computer_name is already joined to 
Active Directory domain, output:\n" . join("\n", @$output));
+               $reboot_after_join = 0;
+       }
        else {
                notify($ERRORS{'OK'}, 0, "executed PowerShell script to join 
$computer_name to Active Directory domain, output:\n" . join("\n", @$output));
        }
-
-       # Reboot, computer should be joined to AD with the correct hostname
-       # If computer had to be rebooted to be renamed, certain tasks in 
reboot() don't need to be performed again
-       # Set reboot()'s last $pre_configure flag accordingly
-       my $ad_join_reboot_pre_configure = ($rename_computer_reboot_duration ? 
0 : 1);
        
-       my $ad_join_reboot_start = time;
-       if (!$self->reboot(300, 3, 1, $ad_join_reboot_pre_configure)) {
-               notify($ERRORS{'WARNING'}, 0, "failed to join $computer_name to 
Active Directory domain, failed to reboot computer after it joined the domain");
-               return;
+       if ($reboot_after_join) {
+               # Reboot, computer should be joined to AD with the correct 
hostname
+               # If computer had to be rebooted to be renamed, certain tasks 
in reboot() don't need to be performed again
+               # Set reboot()'s last $pre_configure flag accordingly
+               my $ad_join_reboot_pre_configure = 
($rename_computer_reboot_duration ? 0 : 1);
+               
+               my $ad_join_reboot_start = time;
+               if (!$self->reboot(300, 3, 1, $ad_join_reboot_pre_configure)) {
+                       notify($ERRORS{'WARNING'}, 0, "failed to join 
$computer_name to Active Directory domain, failed to reboot computer after it 
joined the domain");
+                       return;
+               }
+               $ad_join_reboot_duration = (time - $ad_join_reboot_start);
+       }
+       else {
+               notify($ERRORS{'DEBUG'}, 0, "$computer_name does NOT need to be 
rebooted because it was already joined to the domain");
        }
-       $ad_join_reboot_duration = (time - $ad_join_reboot_start);
        
        my $total_duration = (time - $start_time);
        my $other_tasks_duration = ($total_duration - 
$rename_computer_reboot_duration - $ad_join_reboot_duration);
        
-       notify($ERRORS{'DEBUG'}, 0, "successfully joined $computer_name to 
Active Directory domain: $domain_dns_name, time statistics:\n" .
-               "computer rename reboot : $rename_computer_reboot_duration 
seconds\n" .
-               "AD join reboot         : $ad_join_reboot_duration seconds\n" .
-               "other tasks            : $other_tasks_duration seconds\n" .
-               "total                  : $total_duration seconds"
-       );
-       return 1;
+       # Verify computer is now in the correct AD domain
+       my $current_domain = $self->ad_get_current_domain();
+       if (!$current_domain) {
+               notify($ERRORS{'WARNING'}, 0, "attempted to join $computer_name 
to $domain_dns_name domain but name of domain computer is currently joined to 
could not be retrieved, PowerShell script execution output:\n" . join("\n", 
@$output));
+               return;
+       }
+       elsif ($domain_dns_name !~ /^$current_domain/) {
+               notify($ERRORS{'WARNING'}, 0, "attempted to join $computer_name 
to $domain_dns_name domain but computer is currently joined to $current_domain 
domain, PowerShell script execution output:\n" . join("\n", @$output));
+               return;
+       }
+       else {
+               notify($ERRORS{'DEBUG'}, 0, "successfully joined $computer_name 
to Active Directory domain: $domain_dns_name, time statistics:\n" .
+                       "computer rename reboot : 
$rename_computer_reboot_duration seconds\n" .
+                       "AD join reboot         : $ad_join_reboot_duration 
seconds\n" .
+                       "other tasks            : $other_tasks_duration 
seconds\n" .
+                       "-------------------------------------\n" .
+                       "total                  : $total_duration seconds"
+               );
+               return 1;
+       }
 }
 
 #//////////////////////////////////////////////////////////////////////////////
@@ -13940,7 +13967,7 @@ sub ad_join_wmic {
                notify($ERRORS{'OK'}, 0, "joined $computer_name to Active 
Directory domain $domain_dns_name using wmic.exe");
        }
        elsif (my $error_message = $error_messages->{$join_return_value}) {
-               notify($ERRORS{'WARNING'}, 0, "failed to join $computer_name to 
Active Directory domain $domain_dns_name using wmic.exe\nreason: 
$error_message\noutput:\n$join_output_string");
+               notify($ERRORS{'WARNING'}, 0, "failed to join $computer_name to 
Active Directory domain $domain_dns_name using wmic.exe, reason: 
$error_message\noutput:\n$join_output_string");
                return;
        }
        else {
@@ -14091,7 +14118,7 @@ sub ad_unjoin {
        #}
        #EOF
        #
-       #       my ($exit_status, $output) = 
$self->run_powershell_as_script($ad_powershell_script, 1, 1);
+       #       my ($exit_status, $output) = 
$self->run_powershell_as_script($ad_powershell_script, 0, 0);
        #       if (!defined($output)) {
        #               notify($ERRORS{'WARNING'}, 0, "failed to execute 
PowerShell script to remove $computer_name from Active Directory domain");
        #               return;
@@ -14227,9 +14254,9 @@ sub ad_search {
        my $domain_dns_name;
        my $domain_username;
        my $domain_password;
-       if (defined($arguments->{domain_dns_name})) {
+       if (defined($arguments->{domain_dns_name}) && 
$arguments->{domain_dns_name} ne $self->data->get_image_domain_dns_name()) {
                $domain_dns_name = $arguments->{domain_dns_name};
-               ($domain_username, $domain_password) = 
get_active_directory_domain_credentials($domain_dns_name);
+               ($domain_username, $domain_password) = 
$self->data->get_domain_credentials($domain_dns_name);
                if (!defined($domain_username) || !defined($domain_password)) {
                        notify($ERRORS{'WARNING'}, 0, "unable to search domain: 
$domain_dns_name, domain DNS name argument was specified but credentials could 
not be determined from existing 'addomain' table entries");
                        return;
@@ -14277,17 +14304,31 @@ sub ad_search {
        $ldap_filter .= ')' if ($search_attribute_count > 1);
        notify($ERRORS{'DEBUG'}, 0, "assembled LDAP filter: '$ldap_filter'");
        
+       my $domain_user_string = "$domain_username\@$domain_dns_name";
+       
+       # Escape single quotes by doubling them
+       (my $domain_password_escaped = $domain_password) =~ s/(['])/$1$1/g;
+       
+       my $delete = ($operation eq 'delete' ? 1 : 0);
        
        # Assemble the PowerShell script
-       my $powershell_script_contents = <<'EOF';
-$Host.UI.RawUI.BufferSize = New-Object Management.Automation.Host.Size(5000, 
500)
+       my $powershell_script_contents = <<EOF;
+\$Host.UI.RawUI.BufferSize = New-Object Management.Automation.Host.Size(5000, 
500)
+Clear-Host
+
+\$domain_dns_name = '$domain_dns_name'
+\$domain_username = '$domain_user_string'
+\$domain_password = '$domain_password_escaped'
+\$ldap_filter = '$ldap_filter'
+\$delete = '$delete'
+
+Write-Host "domain: $domain_dns_name"
+Write-Host "domain username (between >*<): >\$domain_username<"
+Write-Host "domain password (between >*<): >\$domain_password<"
 
-$domain_dns_name = '[domain_dns_name]'
-$domain_username = '[domain_username]@[domain_dns_name]'
-$domain_password = '[domain_password]'
-$ldap_filter = '[ldap_filter]'
-$delete = '[delete]'
+EOF
 
+       $powershell_script_contents .= <<'EOF';
 $type = [System.DirectoryServices.ActiveDirectory.DirectoryContextType]"Domain"
 $directory_context = New-Object 
System.DirectoryServices.ActiveDirectory.DirectoryContext($type, 
$domain_dns_name, $domain_username, $domain_password)
 try {
@@ -14350,21 +14391,9 @@ ForEach($result in $results) {
 }
 EOF
        
-       $powershell_script_contents =~ s/\[domain_dns_name\]/$domain_dns_name/g;
-       $powershell_script_contents =~ s/\[domain_username\]/$domain_username/g;
-       $powershell_script_contents =~ s/\[domain_password\]/$domain_password/g;
-       $powershell_script_contents =~ s/\[ldap_filter\]/$ldap_filter/;
-       
-       if ($operation eq 'delete') {
-               $powershell_script_contents =~ s/\[delete\]/1/g;
-       }
-       else {
-               $powershell_script_contents =~ s/\[delete\]/0/g;
-       }
-       
        my ($exit_status, $output);
        for (my $attempt=1; $attempt<=$attempt_limit; $attempt++) {
-               ($exit_status, $output) = 
$self->run_powershell_as_script($powershell_script_contents);
+               ($exit_status, $output) = 
$self->run_powershell_as_script($powershell_script_contents, 0, 0);
                if (!defined($output)) {
                        notify($ERRORS{'WARNING'}, 0, "failed to execute 
PowerShell script on $computer_name to $operation objects in $domain_dns_name 
AD domain matching LDAP filter: '$ldap_filter'");
                        return;
@@ -14388,13 +14417,15 @@ EOF
        
        my @matching_dns;
        for my $line (@$output) {
+               next if ($line !~ /\w/);
+               
                # Remove leading and trailing spaces
                $line =~ s/(^\s+|\s+$)//g;
                if ($line =~ /^[A-Z]{2}=.+/i) {
                        push @matching_dns, $line;
                }
-               else {
-                       notify($ERRORS{'WARNING'}, 0, "unexpected output found 
$operation objects on $computer_name in $domain_dns_name AD domain matching 
LDAP filter: '$ldap_filter': '$line'");
+               elsif ($line !~ /^domain.*:/) {
+                       notify($ERRORS{'WARNING'}, 0, "unexpected output found 
$operation objects on $computer_name in $domain_dns_name AD domain matching 
LDAP filter: '$ldap_filter':\n$line");
                }
        }
        
@@ -14474,7 +14505,7 @@ sub ad_search_computer {
                return;
        }
        
-       my ($computer_samaccountname, $domain_dns_name) = @_;
+       my ($computer_samaccountname, $domain_dns_name, $ad_search_arguments) = 
@_;
        
        $computer_samaccountname = $self->data->get_computer_short_name() 
unless $computer_samaccountname;
        
@@ -14482,12 +14513,8 @@ sub ad_search_computer {
        # A dollar sign will be present if retrieved directly from AD
        $computer_samaccountname =~ s/\$*$/\$/g;
        
-       my $ad_search_arguments = {
-               'ldap_filter' => {
-                       'objectClass' => 'computer',
-                       'sAMAccountName' => $computer_samaccountname,
-               }
-       };
+       $ad_search_arguments->{ldap_filter}{objectClass} = 'computer';
+       $ad_search_arguments->{ldap_filter}{sAMAccountName} = 
$computer_samaccountname;
        
        # If a specific domain was specified, retrieve the username and 
password for that domain
        if ($domain_dns_name) {

Modified: vcl/trunk/managementnode/lib/VCL/utils.pm
URL: 
http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/utils.pm?rev=1797800&r1=1797799&r2=1797800&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/utils.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/utils.pm Tue Jun  6 16:09:58 2017
@@ -118,7 +118,6 @@ our @EXPORT = qw(
        format_data
        format_hash_keys
        format_number
-       get_active_directory_domain_credentials
        get_all_reservation_ids
        get_affiliation_info
        get_array_intersection
@@ -162,6 +161,7 @@ our @EXPORT = qw(
        get_imagerevision_reservation_info
        get_local_user_info
        get_managable_resource_groups
+       get_management_node_ad_domain_credentials
        get_management_node_blockrequests
        get_management_node_computer_ids
        get_management_node_id
@@ -8687,9 +8687,10 @@ sub get_calling_subroutine {
 
 =head2 get_management_node_id
 
- Parameters  :
- Returns     :
- Description :
+ Parameters  : none
+ Returns     : integer
+ Description : Retrieves the managementnode.id value of the local management
+               node.
 
 =cut
 
@@ -8698,7 +8699,6 @@ sub get_management_node_id {
 
        # Check the management_node_id environment variable
        if ($ENV{management_node_id}) {
-               notify($ERRORS{'DEBUG'}, 0, "environment variable: 
$ENV{management_node_id}");
                return $ENV{management_node_id};
        }
        else {
@@ -14603,61 +14603,6 @@ EOF
 
 #//////////////////////////////////////////////////////////////////////////////
 
-=head2 get_active_directory_domain_credentials
-
- Parameters  : $domain_dns_name, $no_cache (optional)
- Returns     : ($username, $password)
- Description : Attempts to retrieve the username and password for the domain
-               from the addomain table. This is used if a computer needs to be
-               removed from a domain but the reservation image is not 
configured
-               for Active Directory. When this occurs, the credentials are not
-               available from $self->data.
-
-=cut
-
-sub get_active_directory_domain_credentials {
-       my ($domain_dns_name, $no_cache) = @_;
-       if (!$domain_dns_name) {
-               notify($ERRORS{'WARNING'}, 0, "domain DNS name argument was not 
specified");
-               return;
-       }
-       
-       if (!$no_cache && 
defined($ENV{active_directory_domain_credentials}{$domain_dns_name})) {
-               notify($ERRORS{'DEBUG'}, 0, "returning cached Active Directory 
credentials for $domain_dns_name domain");
-               return 
@{$ENV{active_directory_domain_credentials}{$domain_dns_name}};
-       }
-       
-       # Construct the select statement
-       my $select_statement = <<EOF;
-SELECT DISTINCT
-username,
-password
-FROM
-addomain
-WHERE
-addomain.domainDNSName = '$domain_dns_name'
-EOF
-       
-       # Call the database select subroutine
-       my @selected_rows = database_select($select_statement);
-
-       # Check to make sure 1 row was returned
-       if (scalar @selected_rows == 0) {
-               notify($ERRORS{'DEBUG'}, 0, "Active Directory domain does not 
exist in the database: $domain_dns_name");
-               return ();
-       }
-
-       # Get the single row returned from the select statement
-       my $row = $selected_rows[0];
-       my $username = $row->{username};
-       my $password = $row->{password};
-       notify($ERRORS{'DEBUG'}, 0, "retrieved credentials for $domain_dns_name 
domain from database, username: '$username', password: '$password'");
-       $ENV{active_directory_domain_credentials}{$domain_dns_name} = 
[$username, $password];
-       return @{$ENV{active_directory_domain_credentials}{$domain_dns_name}};
-}
-
-#//////////////////////////////////////////////////////////////////////////////
-
 =head2 get_collapsed_hash_reference
 
  Parameters  : $hash_reference
@@ -15090,6 +15035,80 @@ EOF
 }
 
 #//////////////////////////////////////////////////////////////////////////////
+
+=head2 get_management_node_ad_domain_credentials
+
+ Parameters  : $management_node_id, $domain_dns_name, $no_cache (optional)
+ Returns     : ($username, $secret_id, $encrypted_password)
+ Description : Attempts to retrieve the username, encrypted password, and 
secret
+               ID for the domain from the addomain table. This is used if a
+               computer needs to be removed from a domain but the reservation
+               image is not configured for Active Directory. When this occurs,
+               the credentials are not available from $self->data.
+
+=cut
+
+sub get_management_node_ad_domain_credentials {
+       my ($management_node_id, $domain_identifier, $no_cache) = @_;
+       if (!defined($management_node_id)) {
+               notify($ERRORS{'WARNING'}, 0, "management node ID argument was 
not supplied");
+               return;
+       }
+       elsif (!$domain_identifier) {
+               notify($ERRORS{'WARNING'}, 0, "domain identifier name argument 
was not specified");
+               return;
+       }
+       
+       if (!$no_cache && 
defined($ENV{management_node_ad_domain_credentials}{$domain_identifier})) {
+               notify($ERRORS{'DEBUG'}, 0, "returning cached Active Directory 
credentials for domain: $domain_identifier");
+               return 
@{$ENV{management_node_ad_domain_credentials}{$domain_identifier}};
+       }
+       
+       # Construct the select statement
+       my $select_statement = <<EOF;
+SELECT DISTINCT
+username,
+password,
+secretid
+FROM
+addomain
+WHERE
+EOF
+       
+       if ($domain_identifier =~ /^\d+$/) {
+               $select_statement .= "addomain.id = $domain_identifier";
+       }
+       else {
+               $select_statement .= "addomain.domainDNSName LIKE 
'$domain_identifier%'";
+       }
+       
+       # Call the database select subroutine
+       my @selected_rows = database_select($select_statement);
+
+       # Check to make sure 1 row was returned
+       if (scalar @selected_rows == 0) {
+               notify($ERRORS{'DEBUG'}, 0, "Active Directory domain does not 
exist in the database: $domain_identifier");
+               return ();
+       }
+
+       # Get the single row returned from the select statement
+       my $row = $selected_rows[0];
+       my $username = $row->{username};
+       my $secret_id = $row->{secretid};
+       my $encrypted_password = $row->{password};
+       
+       
+       
+       notify($ERRORS{'DEBUG'}, 0, "retrieved credentials for domain: 
$domain_identifier\n" .
+               "username           : '$username'\n" .
+               "secret ID          : '$secret_id'\n" .
+               "encrypted password : '$encrypted_password'"
+       );
+       $ENV{management_node_ad_domain_credentials}{$domain_identifier} = 
[$username, $secret_id, $encrypted_password];
+       return 
@{$ENV{management_node_ad_domain_credentials}{$domain_identifier}};
+}
+
+#//////////////////////////////////////////////////////////////////////////////
 
 =head2 delete_management_node_cryptsecret
 


Reply via email to