Install of ADC DSfW server fails in DNS task

  • 7010158
  • 14-Feb-2012
  • 27-Apr-2012

Environment

Novell Open Enterprise Server 2 SP1 (OES2SP1)
Novell Open Enterprise Server 2 SP2 (OES2SP2)
Novell Open Enterprise Server 2 SP3 (OES2SP3)
Novell Open Enterprise Server 11 (OES11)
Domain Services for Windows
DSfW

Situation

Install of ADC DSfW server fails in DNS task

The DNS record the task it attempting to modify does not exist.

The /var/opt/novell/xad/log/provision.log shows the following:

2012-01-25 11:45:32 proceeding with the next entry
2012-01-25 11:45:32 /opt/novell/xad/lib64/perl/NDS/import.pm:103 Could not process the entry
2012-01-25 11:45:32 /opt/novell/xad/lib64/perl/NDS/import.pm:104
2012-01-25 11:45:32 /opt/novell/xad/lib64/perl/NDS/import.pm:105 LDAP_NO_SUCH_OBJECT:The server cannot find an object specified in the request

Could not import /var/opt/novell/xad/ds/dns/final-fwdzone-records.ldif at /opt/novell/xad/lib64/perl/XAD/dns.pm line 435, <DATA> line 16894.
 at /opt/novell/xad/lib64/perl/Logger.pm line 119
    Logger::_err('Could not import /var/opt/novell/xad/ds/dns/final-fwdzone-rec...') called at /opt/novell/xad/lib64/perl/Logger.pm line 206
    Logger::Log(0, 'Could not import /var/opt/novell/xad/ds/dns/final-fwdzone-rec...') called at /opt/novell/xad/lib64/perl/XAD/dns.pm line 472
    dns::configure_zone_rr_object() called at /opt/novell/xad/lib64/perl/Install/adc_install.pm line 296
    eval {...} called at /opt/novell/xad/lib64/perl/Install/adc_install.pm line 278
    adc_install::configure_zone_rr_object('adc_install=HASH(0x793080)') called at /opt/novell/xad/share/dcinit/provision/provision_dns.pl line 28
2012-01-25 11:45:32 /opt/novell/xad/lib64/perl/XAD/dns.pm:429 Could not import /var/opt/novell/xad/ds/dns/final-fwdzone-records.ldif
2012-01-25 11:45:32,149 INFO  - DNS Configuration:DNS Configuration returned.

Taking an ldap trace shows:

DoModify on connection 0x11e57000
modify: dn (cn=\#ldap_#tcp_63cf1b8c-7407-454a-9db1-8c1bcf630774_domains_#msdcs,cn=dsfw_lan,ou=OESSystemObjects,o=novell)
 Cannot resolve NDS name 'CN=#ldap_#tcp_63cf1b8c-7407-454a-9db1-8c1bcf630774_domains_#msdcs.CN=dsfw_lan.OU=OESSystemObjects.O=fnovell' in ResolveAndAuthNDSName, err = no such entry (-601)
 Base "cn=\#ldap_#tcp_63cf1b8c-7407-454a-9db1-8c1bcf630774_domains_#msdcs,ou=OESSystemObjects,o=novell" not found, err = no such entry (-601)
 Sending operation result 32:"cn=dsfw_lan,ou=OESSystemObjects,o=novell":"NDS error: no such entry (-601)" to connection 0x11e57000
Monitor 0x4ae16700 found connection 0x11e57000 ending TLS session
DoTLSShutdown on connection 0x11e57000

Resolution

DSfW was previously installed and removed, but not properly cleaned up.  The Domain Guid might night have been cleaned up from the object where the domain was mapped to and the dns record containing the guid was not removed.

 (the <domain guid> will list the domain guid number)
_ldap._tcp.<domain guid>.domains._msdcs
Example of a record
_msdcs.domain.com._ldap._tcp.12b0ca11-b91a-5eca-3b71-1cab05613a9b.domains SRV 0 100 389 frd.domain.com

To determine if the dns record domain guid number is correct run the following command:
/opt/novell/xad/share/dcinit/provisionTools.sh get-domain-guid -p <PDC-IP-ADDR> -c <MAPPED-CONTEXT-OF-DOMAIN>

example:
/opt/novell/xad/share/dcinit/provisionTools.sh get-domain-guid -p 192.168.0.10 -c o=novell

If the number returned is different than the number in the dns record, the record needs to be created properly.

Create and run the "upgrade_dns_data.pl" script listed in the additional information section of this TID with the -g switch

See also TID 7005314

Additional Information

#!/usr/bin/perl
####################################################
#
#   (C) Copyright 2009-2010 Novell, Inc.
#  All Rights Reserved.
#
#   This program is an unpublished copyrighted work which is proprietary
#   to Novell, Inc. and contains confidential information that is not
#   to be reproduced or disclosed to any other person or entity without
#   prior written consent from Novell, Inc. in each and every instance.
#
#   WARNING:  Unauthorized reproduction of this program as well as
#   unauthorized preparation of derivative works based upon the
#   program or distribution of copies by sale, rental, lease or
#   lending are violations of federal copyright laws and state trade
#   secret laws, punishable by civil and criminal penalties.
#
#####################################################

use strict;
use warnings;
use Getopt::Std;
use MIME::Base64;
use Term::ReadKey;
use Net::LDAP;
use Net::LDAPS;
use Net::LDAP::Util qw(ldap_error_text
                         ldap_error_name
                         ldap_error_desc
                        );                                              #SSL bind
use Net::LDAP::LDIF;
use Net::LDAP::Control;
use Net::LDAP::Constant qw( LDAP_CONTROL_MATCHEDVALS );

my $dry_run = 0;
my $username = "";
my $password = "";
my $ld;
my ($domainname, $domain_container, $zone_name);

my %RR_Types_maps = (
    "A"        => "1",
    "NS"        => "2",
    "CNAME"        => "5",
    "PTR"        => "12",
    "SRV"        => "33"
    );

my %RR_value = (
    "RR_Type"    => "$RR_Types_maps{SRV}",
    "RR_Adr_Class"    => "1",
    "RR_TTL"    => "0",
    "RR_Data_len"    => ""
    );

my %RR_Data_Value = (
    "Priority"    => "0",
    "Weight"    => "100",
    "Port"        => "389",
    "Data"        => ""
    );


sub usage
{
    print <<USE;
 This script fixes two dns problems which will help to make the upgrade smooth.
    dsfw-fix-sp1-dns-records.pl [-g] [-r] [-a] [-h]
    -g    Fix the unknown domain guid record
    -r    Fix the rr record length problem
    -a    Fix both of the above problem
    -D    Administrator name
    -w    Password for the Administrator
    -n    dry run
    -h    Print this help

USE
}

sub read_pwd_terminal
{
    my $str = shift;
    my $pwd;

    print "\n$str: ";

    ReadMode('noecho');
    $pwd = ReadLine(0);
    ReadMode('normal');

    print "\n";
    chomp($pwd);
    return $pwd;
}

sub initiate_connection_variables
{
    $ld = Net::LDAP->new("localhost", scheme=>"ldaps", port=>"636", timeout=>120) or die("Could not create connection");
    my $msg = $ld->bind($username, password=>$password);
    $msg->code && die $msg->error;

    if (ldap_error_name($msg) ne "LDAP_SUCCESS") {
        die(ldap_error_text($msg));
    }

    $domainname = `/bin/dnsdomainname`;
    chomp($domainname);

    $domain_container = "dc=$domainname";
    $domain_container =~ s/\./,dc=/g;

    $zone_name = "cn=$domainname,ou=oessystemobjects,$domain_container";
    $zone_name =~ s/\./_/g;


}

sub get_credential
{
    if($username eq "")
    {
        if(defined $ENV{ADM_NAME})
        {
            $username = $ENV{ADM_NAME}
        }
        else
        {
            print "Username is neither passed with -D flag or with ADM_NAME environement variable.\n";
            my $domain = `/bin/dnsdomainname`;
            chomp($domain);
            $domain =~ s/\./,dc=/;
            print "Assuming the default administrator : cn=Administrator,cn=users,dc=$domain\n";
            $username = "cn=Administrator,cn=users,dc=$domain";
        }
    }

    if($password eq  "")
    {
        if(defined $ENV{ADM_PASSWD})
        {
            $password = $ENV{ADM_PASSWD};
        }
        else
        {
            $password = read_pwd_terminal("Enter the password for the administrator")
        }           
    }

    initiate_connection_variables;
}

sub fix_domain_guid
{
    print "\nGetting the domain container..\n";

    print "Domain container = $domain_container\n\n";

    print "Getting the correct domain guid...\n";
    my $domain_guid = `/opt/novell/xad/share/dcinit/provisionTools.sh get-domain-guid -p localhost -c $domain_container`;

    if($? == 0) {
        chomp($domain_guid);
    }
    else {
        print "Could not get the domain guid using, \n";
        print "/opt/novell/xad/share/dcinit/provisionTools.sh get-domain-guid -p localhost -c $domain_container\n";
        exit(1);
    }

    print "Domain GUID = $domain_guid\n\n";
    print "Searching for the wrong domain guid srv records..\n";

    my $wrong_list = $ld->search(base=>$zone_name,
                scope=>"sub",
               filter=>"(&(cn=#ldap_#tcp_*domains_#msdcs)(!(cn=#ldap_#tcp_".$domain_guid."_domains_#msdcs)))");

    for (my $i=0; $i<$wrong_list->count; $i++)
    {
        my $ent = $wrong_list->entry( $i );
        print $ent->dn(). "\n";
    }

    $| = 1; # perform flush after each write to STDOUT
    print "The above records will be corrected to $domain_guid \n";
    print "(P)roceed:";

    my $c;
    $c = ReadLine(0);
    chomp($c);
#    sysread(STDIN,$c,1);
    if(lc($c) eq "p"){
        my $entry;

        print "\n Proceeding further\n";
        my $out = $ld->search(base=>$zone_name,
                scope=>"one",
                filter=>"cn=#ldap_#tcp_"."$domain_guid"."_domains_#msdcs");

        if($out->count == 1) {

            print "cn=#ldap_#tcp_"."$domain_guid"."_domains_#msdcs,$zone_name already exist, modifying it\n";
            $entry = $out->entry(0);

            for (my $i=0; $i<$wrong_list->count; $i++)
            {
                my $ent = $wrong_list->entry( $i );
                my $dn = $ent->dn;
                next if $dn =~ /$domain_guid/; #skiping the same entries content
                my $val = $ent->get_value('dNIPRR');
                $entry->add('dNIPRR' => $val);
            }
       
        }
        else {

            print "Creating cn=#ldap_#tcp_"."$domain_guid"."_domains_#msdcs,$zone_name\n";
            $entry =  Net::LDAP::Entry->new();
            $entry->dn( "cn=\\#ldap_#tcp_".$domain_guid."_domains_#msdcs,$zone_name");
            $entry->add('objectClass' => [qw( top dNIPDNSRRset )]);
            $entry->add('dNIPRRStatus' => 0);
            $entry->add('dNIPDNSDomainName' =>"_ldap._tcp.$domain_guid.domains._msdcs.$domainname" );

            for (my $i=0; $i<$wrong_list->count; $i++)
            {
                my $ent = $wrong_list->entry( $i );
                my $val = $ent->get_value('dNIPRR');
                $entry->add('dNIPRR' => $val);
            }

        }

        if ($dry_run == 0) {
            my $msg = $entry->update($ld);           
            $msg->code && die $msg->error;

            if (ldap_error_name($msg) ne "LDAP_SUCCESS") {
                print "Could not create the correct domain guid entry";
                die(ldap_error_text($msg));
            }
        }

        for (my $i=0; $i<$wrong_list->count; $i++)
        {
            my $ent = $wrong_list->entry( $i );
            $ent->delete();
            if($dry_run == 0) {   
                my $msg = $ent->update($ld);

                $msg->code && die $msg->error;
                if (ldap_error_name($msg) ne "LDAP_SUCCESS") {
                    print "Could not delete the old wrong domain guid entries";
                    die(ldap_error_text($msg));
                }
            }
        }
       
    }
    else {
        print "\n Not proceeding further\n";
        return;
    }
    print "Correct domain guid record is created\n";
}

sub Form_Data_format {
    my ($data_string) = @_;
    my (@data_array, @data_member_length, @aggregate_array) = "";
    my ($data_array_length, $i, $j) = 0;
    my ($final_data_string, $datapackstring);

    $data_string =~ s/\./_/g;
    @data_array = split("_", $data_string);
    $data_array_length = @data_array;
    $datapackstring = "ca";

    for($i=0; $i < $data_array_length; $i++)
    {
        $data_member_length[$i] = length($data_array[$i]);
        $datapackstring .= length($data_array[$i])."ca";
    }

    # chop off the last two added 'ca' to datapackstring
    chop $datapackstring;
    chop $datapackstring;

    for($i=0, $j=0; $i < $data_array_length; $i++, $j=$j+2)   
    {
        $aggregate_array[$j] = $data_member_length[$i];
        $aggregate_array[$j+1] = $data_array[$i];
    }
    # create the final data string
    $final_data_string = join(',', @aggregate_array);

    return ($final_data_string, $datapackstring);
}

sub fix_rr_length
{

    print "\n\n Finding the pdc record with the wrong length\n\n";
    my %rr_list = ();
    my $out = $ld->search(base=>"ou=Domain Controllers,$domain_container",
            scope=>"one",
            filter=>"objectclass=computer");

    #We need to get the domain controller fqdn. Search under ou=Domain controller
    #and form the DC's fqdn and formulate the dnipRR and compare.
    for(my $i=0; $i<$out->count; $i++) {

        #The problem exist only with the host more than 9 characters
        if(length($out->entry($i)->get_value('cn')) > 9) { ##> 9

            my $dcname = $out->entry($i)->get_value("cn").".$domainname";
            my ($final_data_string, $datapackstring) = Form_Data_format(lc($dcname));
            my @data_array = split(/,/, $final_data_string);
            my $data_len = 0;

            for(my $j=0; $j<@data_array; $j+=2)
            {
                #lenth of each word between dots
                $data_len += int($data_array[$j]);
            }
            #one byte to store each word's length
            $data_len += (@data_array)/2;

            my $temp_data_string = $final_data_string;
            $temp_data_string =~ s/,//g;

            # data length = 2 bytes (priority) + 2 byte (weight) + 2 byte (port) +  length(data) in bytes + 1 byte (null char), as the 1 byte of 1st data segment is counted in $data_len now
            $RR_value{RR_Data_correct_len} =  2 + 2 + 2 +  "$data_len" + 1;
            $RR_value{RR_Data_wrong_len} = 2 + 2 + 2 + length($temp_data_string) + 1;

            my $finalpackstring = "nnNnnnn".$datapackstring."x";
            my $finalcorrectbitstring = pack "$finalpackstring", $RR_value{RR_Type}, $RR_value{RR_Adr_Class}, $RR_value{RR_TTL}, $RR_value{RR_Data_correct_len}, $RR_Data_Value{Priority}, $RR_Data_Value{Weight}, $RR_Data_Value{Port}, split(",", "$final_data_string");
            my $finalwrongbitstring = pack "$finalpackstring", $RR_value{RR_Type}, $RR_value{RR_Adr_Class}, $RR_value{RR_TTL}, $RR_value{RR_Data_wrong_len}, $RR_Data_Value{Priority}, $RR_Data_Value{Weight}, $RR_Data_Value{Port}, split(",", "$final_data_string");

            my @arr = [$finalwrongbitstring, $finalcorrectbitstring];
            $rr_list{$dcname}{wrong} = $finalwrongbitstring;
            $rr_list{$dcname}{correct} = $finalcorrectbitstring;

        }
    }

    $out = $ld->search(base=>$zone_name,
            scope=>"one",
            filter=>"cn=#ldap_#tcp_pdc_#msdcs");
    my $entry;

    if($out->count == 1) {
        $entry = $out->entry(0);
    }
    else {
        print "Could not find the pdc record, exiting";
        exit(1);
    }

    my @rr_vals = $entry->get_value('dNIPRR');
    foreach my $rr_val (@rr_vals) {
        for my $key (keys %rr_list) {
            if ($rr_list{$key}{wrong} eq $rr_val) {
                print "$key contains wrong length in the pdc record (dNIPRR)\n";
                $entry->delete('dNIPRR'=>[$rr_val]);
                $entry->add('dNIPRR'=>[$rr_list{$key}{correct}]);
            }
        }
    }

    $| = 1; # perform flush after each write to STDOUT
    print "The above domain controller name will be fixed in the pdc record \n";
    print "(P)roceed:";

    my $c;
    $c = ReadLine(0);
    chomp($c);
#    sysread(STDIN,$c,1);
    if(lc($c) eq "p"){
        print "\n Proceeding further\n";
        if ($dry_run == 0) {
            my $msg = $entry->update($ld);

            $msg->code && die $msg->error;
            if (ldap_error_name($msg) ne "LDAP_SUCCESS") {
                print "Could not fix the dniprr attribute of the pdc record";
                die(ldap_error_text($msg));
            }
        }
    }
    else {
        print "\n Not proceeding further\n";
        exit(0);
    }
   
    print "The pdc record is fixed. ddns update will happen correctly\n";
}


sub main
{
    my %options=();
    getopts("granhD:w:", \%options) or die("Unexpected arguments");
    my $count = scalar keys %options;
    print "\n\n";

    $dry_run = 1 if defined $options{n};
    $username = $options{D} if defined $options{D};
    $password = $options{w} if defined $options{w};

    if (defined $options{h} || $count == 0) {
        usage
    }
    elsif (defined $options{a})
    {
        get_credential;
        fix_domain_guid;
        fix_rr_length;
    }
    elsif (defined $options{g})
    {
        get_credential;
        fix_domain_guid;
    }
    elsif (defined $options{r})
    {
        get_credential;
        fix_rr_length;
    }
    else
    {
        usage;
    }
}

main