#!/usr/bin/perl -w # # # Comments on usage from the email we received: # I showed a friend the following script. He said I should submit it for # inclusion in openldap, because it might useful for others. # # The attached perl script, when used like # # ldapsearch | ldiftopasswd # # will automatically: # # 1. create /etc/passwd, /etc/shadow, /etc/group, and /etc/gshadow # # 2. append /etc/passwd.top, /etc/shadow.top, /etc/group.top, and /etc/gshadow.top to respective files. # # 3. use data from ldap to create the files (note: gshadow isn't really # supported, because I don't use it, nor could I find any # documentation. Adding support for other files should be easy). # # (of course you need access to all fields including the password field # for this, so use correct parameters to ldapsearch). # # This could be useful for instance on laptop computers where you don't # want to run a slave slapd server for some reason (perhaps memory # constraints). # ---------------------------------------- use strict; use Getopt::Long; use MIME::Base64; use IO::File; my $passwdfile="/etc/passwd"; my $shadowfile="/etc/shadow"; my $groupfile="/etc/group"; my $gshadowfile="/etc/gshadow"; my $help; GetOptions ( '--passwd=s',\$passwdfile, '--shadow=s',\$shadowfile, '--group=s',\$groupfile, '--gshadow=s',\$gshadowfile, '--help',\$help, ) or die "Bad options\n"; if ($help or $#ARGV != -1) { print STDERR "usage: $0 [etcfile=filename] [--help]\n"; exit 255; } sub start_file($) { my ($file) = @_; my $outhandle = new IO::File; $outhandle->open(">$file") or die "Cannot open $file for writing"; open(TMP,"<$file.top") or die "cannot open $file.top for reading"; while () { $outhandle->print($_); } close(TMP) or die "cannot close $file for reading"; return($outhandle); } my $PASSWD = start_file($passwdfile); my $SHADOW = start_file($shadowfile); my $GROUP = start_file($groupfile); my $GSHADOW = start_file($gshadowfile); sub dopasswd($) { my ($record) = @_; my $userPassword="*"; $PASSWD->print( $record->{"uid"},":", "x",":", $record->{"uidNumber"},":", $record->{"gidNumber"},":", $record->{"gecos"},":", $record->{"homeDirectory"},":", $record->{"loginShell"},"\n"); if (defined($record->{"userPassword"}) && $record->{"userPassword"} =~ /^{(crypt)}(.*)$/) { $userPassword = $2; } $SHADOW->print( $record->{"uid"},":", $userPassword,":", $record->{"shadowLastChange"} || "10706",":", $record->{"shadowMin"} || "0",":", $record->{"shadowMax"} || "99999",":", $record->{"shadowWarning"} || "7",":", $record->{"shadowInactive"} || "",":", $record->{"shadowExpire"} || "",":", "","\n"); } sub dogroup($) { my ($record) = @_; my $userPassword="*"; my $members=""; if (defined($record->{"memberUid"})) { $members = join(",",@{$record->{"memberUid"}}); } $GROUP->print( $record->{"cn"},":", "x",":", $record->{"gidNumber"},":", $members,"\n"); if (defined($record->{"userPassword"}) && $record->{"userPassword"} =~ /^{(crypt)}(.*)$/) { $userPassword = $2; } # !FIXME! # $GSHADOW->print # $record->{"cn"},":", # "*",":", # "",":", # "","\n"; } my %record; my $user=0; my $group=0; while (<>) { if (/^$/) { if ($user) { dopasswd(\%record); } if ($group) { dogroup(\%record); } $user = $group = 0; %record=(); } elsif (/^objectClass: posixAccount$/) { $user = 1; } elsif (/^objectClass: posixGroup$/) { $group = 1; } elsif (/^(uid|uidNumber|gidNumber|gecos|homeDirectory|loginShell): (.*)$/) { if (!defined($record{$1})) { $record{$1} = $2; } } elsif (/^(userPassword|shadowLastChange|shadowMin|shadowMax|shadowWarning|shadowInactive|shadowExpire): (.*)$/) { if (!defined($record{$1})) { $record{$1} = $2; } } elsif (/^(cn): (.*)$/) { if (!defined($record{$1})) { $record{$1} = $2; } } elsif (/^(uniqueMember): (.*)$/) { push @{$record{$1}},$2; if ($2 =~ /uid=([a-zA-Z]*),/) { push @{$record{"memberUid"}},$1; } } elsif (/^(memberUid): (.*)$/) { push @{$record{$1}},$2; } elsif (/^(userPassword):: (.*)$/) { $record{$1} = decode_base64($2); } } $PASSWD->close or die "Cannot close $passwdfile for writing"; $SHADOW->close or die "Cannot close $shadowfile for writing"; $GROUP->close or die "Cannot close $groupfile for writing"; $GSHADOW->close or die "Cannot close $gshadowfile for writing";