Hack9.Sync LDAP Data with NIS


Hack 9. Sync LDAP Data with NIS

Run a script out of cron to help with a graceful transformation to LDAP.

An NIS-to-LDAP migration is a nontrivial event in any environment. If the switch were as simple as moving data from one place to another, most organizations would've done it by now. The reality in many production environments, large and small, is that some applications (and even appliances) do not yet support LDAP or don't support LDAP to the extent that we would like. Eventually, most places come to terms with LDAP's limitations and implement a "phase in" approach, which involves using LDAP where it is fully supported but keeping NIS around for those things that require it.

In those environments where the authentication source will be NIS for some legacy systems and LDAP for those newer systems that support it, the challenge becomes keeping the data synchronized between NIS and LDAP. Over the past couple of years, I have found several tools that attempt to solve this problem. One is a C program that, though it is amazingly generic, requires a whole bunch of flags that will look quite cryptic to some system administrators. Another solution consisted of a suite of tools that attempted to do too much and weren't very configurable. I was unable to make friends with these tools, as they seemed to make assumptions about my environment that would never be true.

In the end, I did find a Perl script online that had a very elementary structure that anyone could understand. It was clearly written and well commented, but unfortunately it wasn't actually written to complete the job it claimed to do. Rather than continuing my search, I broke down and decided that, by using this Perl script as a "good enough" skeleton, I could get it to work for my needs. Here is my Perl hack for taking data residing in LDAP and creating NIS maps.

1.10.1. The Code

 #!/usr/bin/perl use Net::LDAP; ## CONFIG my $server = "ldap-server"; my $base = "dc=example,dc=com"; my $bind = "uid=ldap2nis,ou=People,dc=example,dc=com"; my $bindpw = 'password'; my $groupf = "group"; my $passwf = "passwd"; my $buildyp = "false"; ## CONNECT my $ldap = Net::LDAP->new($server, onerror => 'die' ); $ldaps = $ldap->start_tls(verify=>'none') or die "Couldn't start tls: $@\n"; $ldap->bind( dn => $bind, password => $bindpw) or die "Bind failed: $@\n"; ## PRINT PASSWORD FILE[1] my $res = $ldap->search( base => $base, scope => 'sub', # entire tree timelimit => 600, filter => '(&(objectClass=posixAccount))', attrs => ['uid', 'uidNumber', 'gidNumber', 'gecos', 'homeDirectory', 'loginShell', 'userPassword'], ); open(PASSWORD, ">$passwf"); while (my $entry = $res->shift_entry) {   (my $uid = $entry->get_value('uid')) =~ s/:/./g;   (my $uidnum = $entry->get_value('uidNumber')) =~ s/:/./g;   (my $gidnum = $entry->get_value('gidNumber')) =~ s/:/./g;   (my $gecos = $entry->get_value('gecos')) =~ s/:/./g;   (my $homedir = $entry->get_value('homeDirectory')) =~ s/:/./g;   (my $shell = $entry->get_value('loginShell')) =~ s/:/./g;   (my $up = $entry->get_value('userPassword')) =~ s/:/./g;   if (index($up, "{crypt}") != -1) {   $up = substr($up, 7);   }else{      $up = crypt($up, "bR");    }    $passrecord = join(':',$uid,$up,$uidnum,$gidnum,$gecos,$homedir,$shell);    print PASSWORD "$passrecord\n"; } close(PASSWORD); chmod(0600, $passwf); ## PRINT GROUP FILE my $res = $ldap->search( base => $base, scope => 'sub', # entire tree timelimit => 600, filter => '(&(objectClass=posixGroup))', attrs => ['cn', 'gidNumber', 'memberuid'], ); open(GROUP, ">$groupf"); while (my $entry = $res->shift_entry) { (my $grname = $entry->get_value('cn')) =~ s/:/./g; my $grpass = "*"; (my $grnum = $entry->get_value('gidNumber')) =~ s/:/./g; (@members = $entry->get_value('memberuid')) =~ s/:/./g; if($#members >= 0) { $memusers = join(',',@members); }else{ $memusers = ""; } $grprecord = join(':', $grname,$grpass,$grnum,$memusers); print GROUP "$grprecord\n";   }   close(GROUP);   chmod(0600, $groupf); 

1.10.2. Running the Code

Assuming you're storing encrypted password strings in your NIS passwd map, this script, which I call dap2nis, should be configured using the variables near the top to bind as an account that has read access to the userPassword attribute for the user entries. Otherwise, you'll get nothing back for that attribute, and your resulting NIS maps won't be useful as authentication sources when they're pushed out.

You can test the code by first making a test directory and making the script executable. Next, be sure to configure it to talk to your LDAP server using the config variables near the top of the script. Once that's all done, running the program should produce passwd and group files in the test directory. These should be valid NIS maps, ready to be pushed out. However, before taking that step, you should run a diff against the current NIS maps to check for any anomalies that reflect errors in the map generation rather than simple changes that have occurred in LDAP but are not yet reflected in NIS. Here are a few commands from a hypothetical test session:

 # ./dap2nis # ypcat passwd > yppass.out # ypcat group > ypgrp.out # diff yppass.out passwd # diff ypgrp.out group 

The only output you should see from the diff commands should be valid changes that have not yet been propagated to NIS. Once you've tested thoroughly, you can put the script in root's crontab file, with an entry like this:

 */7 * * * * /var/adm/bin/dap2nis 

This entry says to run the script every seven minutes, all the time, every day.

The only thing the dap2nis script does not do in its current incarnation is actually perform a cd var/yp/; make, which would normally push out the NIS maps. Depending on your environment, you may not want this in this particular script. Instead, you might put in another cron job that pushes out NIS maps every four minutes, which would allow for changes to be pushed out automatically to reflect changes that were made to maps not covered by this script. Creating a separate cron job to push out the NIS maps also ensures that if this script is ever retired or pulled out of production, your maps will still get pushed out in an automated fashion.

1.10.3. See Also

  • "Centralize Logins with LDAP" [Hack #6]

  • "Authenticate NFS-Lovers with NIS" [Hack #8]

  • "Clean Up NIS After Users Depart" [Hack #77]



Linux Server Hacks (Vol. 2)
BSD Sockets Programming from a Multi-Language Perspective (Programming Series)
ISBN: N/A
EAN: 2147483647
Year: 2003
Pages: 162
Authors: M. Tim Jones

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net